R - 如何根据与另一个数据帧的部分匹配对数据帧中的每一行进行分类?



我有两个数据帧(df1和df2),这里是df1:

SAMPLE NAMES
1_a
1_b
1_c
2_a
2_b
3_a
4_a
4_b

这是 df2:

ID  GROUP   
1   X
2   X
3   Y
4   Z

这就是我想做的 - 我想向 df1 添加一个新列,该列将根据与 df2 的 ID 列的部分匹配来指示样本的组。因此,来自 df1 的样本 "2_a" 和 "2_b" 应与 df2 中的 "2" 具有相同的组。

期望输出:

SAMPLE NAMES    GROUP
1_a             X
1_b             X
1_c             X
2_a             X
2_b             X
3_a             Y
4_a             Z
4_b             Z

到目前为止,我已经尝试使用字符串包并编写一个 for 循环:

for (i in df1[, 1]){
for (j in df2$ID){
x <- which(str_detect(i,j))
class <- df2[j,1]
df1$group[i] <- class
}
}

但它一直给我错误:

使用方法("类型")中的错误: 没有适用于"type"的方法应用于类"c('整数', 'numeric')"的对象

我做错了什么?另外,有没有办法使用 apply() 函数而不是循环来做到这一点?

这是一个tidyverse选项

library(tidyverse)
df1 %>% 
separate(., col = SAMPLE.NAMES, into = c('SAMPLE', 'NAMES'), sep = "_", convert = TRUE) %>% 
left_join(df2, by = c('SAMPLE' = 'ID')) %>% 
unite(., col = SAMPLE.NAMES, SAMPLE, NAMES)
#  SAMPLE.NAMES GROUP
#1          1_a     X
#2          1_b     X
#3          1_c     X
#4          2_a     X
#5          2_b     X
#6          3_a     Y
#7          4_a     Z
#8          4_b     Z

我们首先separate"样本"列。NAMES"df1成两个,这样我们就可以通过"SAMPLE"和"ID"与df2left_joindf1。在最后一行中,我们将"SAMPLE"和"NAME"列unite回"SAMPLE"。名字'。

数据

df1 <- structure(list(SAMPLE.NAMES = structure(1:8, .Label = c("1_a", 
"1_b", "1_c", "2_a", "2_b", "3_a", "4_a", "4_b"), class = "factor")), .Names = "SAMPLE.NAMES", class = "data.frame", row.names = c(NA, 
-8L))
df2 <- structure(list(ID = 1:4, GROUP = structure(c(1L, 1L, 2L, 3L), .Label = c("X", 
"Y", "Z"), class = "factor")), .Names = c("ID", "GROUP"), class = "data.frame", row.names = c(NA, 
-4L))

你的for循环不起作用的主要原因是str_detect()只接受字符串作为输入,但你试图在df2的ID列上使用它,这是一个数字向量。for循环还有其他问题:特别是,您定义了一个对象x该对象之后从未实际使用过,因此您的代码不会使用str_detect()选择所需的元素。

如果您想要更多stringr解决方案,这是另一种选择。它既不使用for循环也不使用apply()(至少不是直接使用)。

它的工作原理是使用正则表达式仅从"SAMPLE.NAMES"列,将每个样本链接到其数字 ID。 之后,我们只需将数据帧连接在一起并选择所需的列:

# Example dataframes
df1 <- tibble(SAMPLE.NAMES = c("1_a", "1_b", "1_c", "2_a", "2_b", "3_a", "4_a", "4_b"))
df2 <- tibble(ID = c(1,2,3,4),
GROUP = c("X", "X", "Y", "Z"))
df1 <- mutate(df1, ID = as.numeric(str_replace_all(SAMPLE.NAMES, "_[abc]", ""))) %>%
left_join(df2) %>%
select(-ID)
# Output:
# A tibble: 8 x 2
SAMPLE.NAMES GROUP
<chr>        <chr>
1 1_a          X    
2 1_b          X    
3 1_c          X    
4 2_a          X    
5 2_b          X    
6 3_a          Y    
7 4_a          Z    
8 4_b          Z  

只需合并下划线之前的字符串部分:

> df1$ID <- sub("_.+$","",df1$SAMPLENAMES)
> df1
SAMPLENAMES ID
1         1_a  1
2         1_b  1
3         1_c  1
4         2_a  2
5         2_b  2
6         3_a  3
7         4_a  4
8         4_b  4
> merge(df1,df2, by="ID")
ID SAMPLENAMES GROUP
1  1         1_a     X
2  1         1_b     X
3  1         1_c     X
4  2         2_a     X
5  2         2_b     X
6  3         3_a     Y
7  4         4_a     Z
8  4         4_b     Z

最新更新