R 在每列中按分隔符排列多列,将字符串与值匹配

R Multiple Columns by Delimiter in each Column, Match String to Value

抱歉这个菜鸟问题,但几天后我还没弄清楚如何做到这一点。我一直在尝试使用R。简单地说,我有两列如下

A:B:C:D:F | 1.1:2.1:3.1:4.1:6.1
A:B:D:F | 1.2:2.2:4.2:6.2
A:B:C:F | 1.3:2.3:3.3:6.3
B:C:D:F | 2.4:3.4:4.4:6.4

请注意分隔符是“:”。最后我想要这个:

A   | B | C | D | E | F
1.1 | 2.1   | 3.1 | 4.1 | NA | 6.1
1.2 | 2.2 | NA  | 4.2   | NA    | 6.2
1.3 | 2.3   | 3.3   | NA    | NA    | 6.3
NA  | 2.4   | 3.4   | 4.4   | NA    | 6.4

为什么我解决不了:

我会想象类似下面的东西,将“1”替换为相应的第 2 列,第 x 行的值,但我不知道该怎么做。我尝试过的另一种方法是在插入第 2 列值时遇到困难,即仅根据是否存在字符串来创建包含 1 和 0 的列,这就是我遇到代码片段的方式。

df$A <- ifelse(grepl("A", df$PASS, ignore.case = T), "1", "0")

抱歉写了这么长的文章,但我实在是卡住了。我觉得这超出了我的初学者水平 R。向任何可以解决这个问题的人致敬!

我们可以试试tidyverse

library(tidyverse)
res <- df1 %>%
        map(~strsplit(., ":")) %>% 
        transpose %>% 
        map(~set_names(as.data.frame.list(as.numeric(.[[2]])), .[[1]]))  %>% 
        bind_rows %>%
        right_join(as.data.frame(setNames(rep(list(NA), 6), LETTERS[1:6])), .) 

res
#    A   B   C   D  E   F
#1 1.1 2.1 3.1 4.1 NA 6.1
#2 1.2 2.2  NA 4.2 NA 6.2
#3 1.3 2.3 3.3  NA NA 6.3
#4  NA 2.4 3.4 4.4 NA 6.4

数据

df1 <- structure(list(col1 = c("A:B:C:D:F", "A:B:D:F", "A:B:C:F", "B:C:D:F"
 ), col2 = c("1.1:2.1:3.1:4.1:6.1", "1.2:2.2:4.2:6.2", "1.3:2.3:3.3:6.3", 
 "2.4:3.4:4.4:6.4")), .Names = c("col1", "col2"), class = "data.frame", 
 row.names = c(NA, -4L))

这里有一个只使用基础 R 的解决方案,没有 tidyverse 的魔力。它假定您可以将所有数据作为一个大字符串读入,但为输入流更改它并不难。

x <- "A:B:C:D:F | 1.1:2.1:3.1:4.1:6.1
A:B:D:F | 1.2:2.2:4.2:6.2
A:B:C:F | 1.3:2.3:3.3:6.3
B:C:D:F | 2.4:3.4:4.4:6.4"

data <- unlist(str_split(x, "\n"))
result <- matrix(as.numeric(NA), nrow = length(data), ncol = 6)
colnames(result) <- c("A", "B", "C", "D", "E", "F")

for (i in 1:length(data)) {
    split_data <- unlist(str_split(data[i], " [|] "))
    print(split_data)
    indices <- unlist(str_split(split_data[1], ":"))
    values <- unlist(str_split(split_data[2], ":"))

    for (j in 1:length(indices)) {
        result[i, indices[j]] <- as.numeric(values[j])
    }
}

result

使用 base R 并以通用格式编写:

使用数据

 df1 <- structure(list(col1 = c("A:B:C:D:F", "A:B:D:F", "A:B:C:F", "B:C:D:F"), col2 = c
("1.1:2.1:3.1:4.1:6.1", "1.2:2.2:4.2:6.2", "1.3:2.3:3.3:6.3", "2.4:3.4:4.4:6.4")),
.Names = c("col1", "col2"), class = "data.frame",  row.names = c(NA, -4L))

那么代码就是

a=apply(df1,1,strsplit,":",fixed=TRUE)
b=lapply(a,function(x){y=`names<-`(as.numeric(x[[2]]),x[[1]]);data.frame(t(y))})
d=Reduce(function(x,y) merge(x,y,by =intersect(names(x),names(y)),all.x = TRUE,all.y = TRUE),b)
b1=max(match(names(unlist(b)),LETTERS))
e=LETTERS[1:b1][!LETTERS[1:b1]%in%names(d)]
f=`names<-`(data.frame(d,rep(list(NA),length(e))),c(names(d),e))
g=f[,order(names(f))]
Reduce(rbind,c(paste0(names(g),collapse = " | "),apply(g,1,paste0,collapse="|")))

如果数据是

 x <- "A:B:C:D:F | 1.1:2.1:3.1:4.1:6.1
       A:B:D:F | 1.2:2.2:4.2:6.2 
       A:B:C:F | 1.3:2.3:3.3:6.3
       B:C:D:F | 2.4:3.4:4.4:6.4"

那么你只需要用下面的一行代码和上面的代码 运行 来转换它。

 df1=matrix(unlist(strsplit(unlist(strsplit(x,"\n"))," | ",fixed = T)),ncol=2,byrow=T)

我建议查看我的 "splitstackshape" 包中的 cSplitdcast:

的组合
library(splitstackshape)
dcast(cSplit(as.data.table(df1)[, id := 1:nrow(df1)], names(df1), ":", "long"), 
      id ~ col1, value.var = "col2")
   id   A   B   C   D   F
1:  1 1.1 2.1 3.1 4.1 6.1
2:  2 1.2 2.2  NA 4.2 6.2
3:  3 1.3 2.3 3.3  NA 6.3
4:  4  NA 2.4 3.4 4.4 6.4