使用从R上的另一列提取的信息创建新列
我有一个数据框,其中一列有多个信息,以“;”分隔,如下所示:使用从R上的另一列提取的信息创建新列,r,string,dplyr,tidyverse,extract,R,String,Dplyr,Tidyverse,Extract,我有一个数据框,其中一列有多个信息,以“;”分隔,如下所示: DF = data.frame(a = c(1,1,1,2,2), b = c('aaa','aaa','aba','abc','ccc'), extra_info = c( 'animal=horse;color=orange;shape=circle', 'animal=monkey;shape=square;value=53
DF = data.frame(a = c(1,1,1,2,2), b = c('aaa','aaa','aba','abc','ccc'),
extra_info = c(
'animal=horse;color=orange;shape=circle',
'animal=monkey;shape=square;value=532',
'animal=horse;color=blue;shape=square;value=321',
'animal=dog;color=green;value=678',
'color=pink;shape=triangle'
))
我不能使用read.table,因为我已经在使用不同的函数来读取数据(而且列extra_info中的每一行的内容都不一样,而且这些列会被弄乱)。我想做的是将所有这些信息分离到不同的列中,并相应地指定专有名称,例如:
a b animal color shape value
1 aaa horse orange circle NA
1 aaa monkey NA square 532
1 aba horse blue square 321
2 abc dog green NA 678
2 ccc NA pink triangle NA
到目前为止,我已经尝试:
new_cols = DF %>% separate(extra_info, c(LETTERS[1:4]), sep = ";")
new_cols %>% separate(A, c("key","value"), sep = '=') %>%
separate(B, c("key","value"), sep = '=') %>%
separate(C, c("key","value"), sep = '=') %>%
separate(D, c("key","value"), sep = '=') %>%
pivot_wider(names_from = c("key"), values_from = c("value"))
但是它并没有像预期的那样工作。使用stringr软件包有点整洁,但是如果您只需要base R,您可以使用以下工具。在
模式中
结构(?%
mutate(color=str_extract(extra_info),(?这里有一种方法,我将键值对的语法更改为有效的JSON语法,并使用jsonlite::fromJSON
解析它:
library(purrr)
library(dplyr)
library(stringr)
library(jsonlite)
DF %>%
mutate(
json = str_replace_all(extra_info, pattern = "\\b", replacement = '"'),
json = str_replace_all(json, pattern = fixed("="), replacement = ":"),
json = str_replace_all(json, pattern = fixed(";"), replacement = ","),
json = paste("{", json, "}"),
) %>%
pull(json) %>%
map(jsonlite::fromJSON) %>%
map(as.data.frame) %>%
bind_rows %>%
cbind(DF, .)
# a b extra_info animal color shape value
# 1 1 aaa animal=horse;color=orange;shape=circle horse orange circle <NA>
# 2 1 aaa animal=monkey;shape=square;value=532 monkey <NA> square 532
# 3 1 aba animal=horse;color=blue;shape=square;value=321 horse blue square 321
# 4 2 abc animal=dog;color=green;value=678 dog green <NA> 678
# 5 2 ccc color=pink;shape=triangle <NA> pink triangle <NA>
库(purrr)
图书馆(dplyr)
图书馆(stringr)
图书馆(jsonlite)
DF%>%
变异(
json=str_replace_all(额外信息,pattern=“\\b”,replacement=”),
json=str_replace_all(json,pattern=fixed(“=”),replacement=“:”,
json=str_replace_all(json,pattern=fixed(“;”),replacement=“,”,
json=粘贴(“{”,json,“}”),
) %>%
拉入(json)%>%
映射(jsonlite::fromJSON)%>%
映射(作为.data.frame)%>%
绑定_行%>%
cbind(DF,.)
#a b额外信息动物颜色形状值
#1 aaa动物=马;颜色=橙色;形状=圆圈马橙色圆圈
#2 1 aaa动物=猴子;形状=正方形;值=532猴子正方形532
#3 1 aba动物=马;颜色=蓝色;形状=正方形;值=321马蓝色正方形321
#4 2 abc动物=狗;颜色=绿色;值=678狗绿色678
#5.2 ccc颜色=粉红色;形状=三角形粉红色三角形
库(stringr)
col_名称%
mutate(animal=str_extract(extra_info,paste0)((?这里是一个使用gsub
+eval
+str2表达式的基本R选项
v <- DF$extra_info
p <- gsub(";", ",", gsub("(?<=\\=)(\\w+)", "'\\1'", v, perl = TRUE))
nms <- unique(unlist(regmatches(v, gregexpr("\\w+(?=\\=)", v, perl = TRUE))))
q <- unname(Map(function(x) setNames(eval(str2expression(x))[nms], nms), sprintf("c(%s)", p)))
cbind(DF[c("a","b")], type.convert(data.frame(do.call(rbind, q)), as.is = TRUE))
v查看tidyr::separate
。这将为您拆分;
上的列。然后运行每一列并对其进行分析。如果您需要更多帮助,请提供一个。感谢您的评论。我尝试了separate,效果非常好,尽管我不知道可能出现的所有信息类型,所以在某些列中有一个不匹配。实际上,您可能可以使用分隔两次
。一次用于;
,一次用于所有结果列,在=
上拆分以分隔为键列和值列。然后您可以使用透视_更宽
将键和值透视到每个键的单独列中。我理解这些步骤,但我不知道aven还没有弄明白如何实现它。我编辑了这篇文章,我认为它现在更容易理解和复制。非常感谢您的帮助!优雅的fromJSON
解决方案!投票赞成!哦,我从这条路线开始,但有点卡住了,切换到了JSON。str2expression
是一个很好的实用程序。这是我最喜欢的工具lution,因为它是以R为基数的,并且是可推广的(我确实有比4更多的列,而且我也不知道所有的列)。然而,我无法在我的数据bc中使用它,我没有涵盖我的示例中可能出现的所有情况(对此我表示歉意)。在现实生活中,我有带空格、逗号、{}的字符串和十进制数。我可以通过用u替换空格和逗号来绕过它们,但我想知道我们是否可以修改RE,使其包含带-,{}和十进制数的大小写。我只是问bc我对RE不太熟悉,但我正在尝试这样做。”可能有一种很好的方法可以在四个单词上写一个循环“是的,我认为这是一个很好的通用解决方案所必需的。我的假设是OP用一个只有4个单词的玩具例子来分享,但是可能还有更多的……
library(purrr)
library(dplyr)
library(stringr)
library(jsonlite)
DF %>%
mutate(
json = str_replace_all(extra_info, pattern = "\\b", replacement = '"'),
json = str_replace_all(json, pattern = fixed("="), replacement = ":"),
json = str_replace_all(json, pattern = fixed(";"), replacement = ","),
json = paste("{", json, "}"),
) %>%
pull(json) %>%
map(jsonlite::fromJSON) %>%
map(as.data.frame) %>%
bind_rows %>%
cbind(DF, .)
# a b extra_info animal color shape value
# 1 1 aaa animal=horse;color=orange;shape=circle horse orange circle <NA>
# 2 1 aaa animal=monkey;shape=square;value=532 monkey <NA> square 532
# 3 1 aba animal=horse;color=blue;shape=square;value=321 horse blue square 321
# 4 2 abc animal=dog;color=green;value=678 dog green <NA> 678
# 5 2 ccc color=pink;shape=triangle <NA> pink triangle <NA>
library(stringr)
col_names <- unlist(str_extract_all(DF$extra_info[3], "(?<=^|;)\\w+"))
DF %>%
mutate(animal = str_extract(extra_info, paste0("(?<=", col_names[1], "=)\\w+")),
color = str_extract(extra_info, paste0("(?<=", col_names[2], "=)\\w+")),
shape = str_extract(extra_info, paste0("(?<=", col_names[3], "=)\\w+")),
value = str_extract(extra_info, paste0("(?<=", col_names[4], "=)\\w+"))
a b extra_info animal color shape value
1 1 aaa animal=horse;color=orange;shape=circle horse orange circle <NA>
2 1 aaa animal=monkey;shape=square;value=532 monkey <NA> square 532
3 1 aba animal=horse;color=blue;shape=square;value=321 horse blue square 321
4 2 abc animal=dog;color=green;value=678 dog green <NA> 678
5 2 ccc color=pink;shape=triangle <NA> pink triangle <NA>
v <- DF$extra_info
p <- gsub(";", ",", gsub("(?<=\\=)(\\w+)", "'\\1'", v, perl = TRUE))
nms <- unique(unlist(regmatches(v, gregexpr("\\w+(?=\\=)", v, perl = TRUE))))
q <- unname(Map(function(x) setNames(eval(str2expression(x))[nms], nms), sprintf("c(%s)", p)))
cbind(DF[c("a","b")], type.convert(data.frame(do.call(rbind, q)), as.is = TRUE))
a b animal color shape value
1 1 aaa horse orange circle NA
2 1 aaa monkey <NA> square 532
3 1 aba horse blue square 321
4 2 abc dog green <NA> 678
5 2 ccc <NA> pink triangle NA