根据字符串的两个数据帧查找索引

时间:2016-07-05 19:21:33

标签: r

我的一个数据输入如下所示:

O75663  O95456  O75663  O95456 
O95400  O95670  O95400  O95670
O95433          O95433  O95801 
                O95456  P00352
                O95670  

df<- structure(
    list(
        V1 = structure(c(2L, 3L, 4L, 1L, 1L), 
            .Label = c("", "O75663", "O95400", "O95433"), 
                class = "factor"), 
        V2 = structure(c(2L, 3L, 1L, 1L, 1L), 
            .Label = c("", "O95456", "O95670"), 
                class = "factor"), 
        V3 = structure(1:5, 
            .Label = c("O75663", "O95400", "O95433", "O95456", "O95670"), 
                class = "factor"), 
        V4 = structure(c(2L, 3L, 4L, 5L, 1L), 
            .Label = c("", "O95456", "O95670", "O95801", "P00352"), 
                class = "factor")), 
    .Names = c("V1", "V2", "V3", "V4"), 
        class = "data.frame", 
        row.names = c(NA, -5L))

我的第二个数据输入如下:

O75663 
O95400 
O95433
O95456 
O95670
O95801 
P00352
P00492

我想知道第二个数据集中的每个字符串,其中可以找到第一个数据的列。它可能不属于任何一个,也可能是几个。我希望输出看起来如下:

strings    column ids 
O75663      1, 3
O95400      1, 3
O95433      1, 3
O95456      2, 3, 4
O95670      2, 3, 4
O95801      4
P00352      4
P00492      NA

新的strs

strs <- structure(
    list(
        strings = structure(c(2L, 3L, 4L, 5L, 6L, 7L, 1L, 1L), 
            .Label = c("", "O75663", "O95400", "O95433", "O95456", "O95670", "O95801"),
                class = "factor"), 
        strings2 = structure(c(4L, 2L, 6L, 5L, 3L, 1L, 1L, 1L), 
            .Label = c("", "O75663", "O95433", "O95456", "P00352", "P00492"), 
                class = "factor"), 
        strings3 = structure(c(4L, 6L, 7L, 8L, 2L, 3L, 5L, 1L), 
            .Label = c("", "O75663", "O95400", "O95456", "O95670", "O95801", "P00352", "P00492"), 
                class = "factor"), 
        strings4 = structure(c(2L, 5L, 3L, 4L, 1L, 1L, 1L, 1L), 
            .Label = c("", "O95400", "O95456", "O95801", "P00492"), 
                class = "factor"), 
        strings5 = structure(c(8L, 2L, 7L, 1L, 3L, 6L, 5L, 4L), 
            .Label = c("O75663", "O95400", "O95433", "O95456", "O95670", "O95801", "P00352", "P00492"), 
                class = "factor")), 
    .Names = c("strings", "strings2", "strings3", "strings4", "strings5"), 
        class = "data.frame", 
        row.names = c(NA, -8L))


lut <- structure(
    list(
        V1 = c("O75663", "O95400", "O95433", NA, NA), 
        V2 = c("O95456", "O95670", NA, NA, NA), 
        V3 = c("O75663", "O95400", "O95433", "O95456", "O95670"), 
        V4 = c("O95456", "O95670", "O95801", "P00352", NA), 
        V1 = c("O75663", "O95400", "O95433", NA, NA), 
        V2 = c("O95456", "O95670", NA, NA, NA), 
        V3 = c("O75663", "O95400", "O95433", "O95456", "O95670"), 
        V4 = c("O95456", "O95670", "O95801", "P00352", NA)), 
    .Names = c("V1", "V2", "V3", "V4", "V1", "V2", "V3", "V4"), 
    row.names = c(NA, -5L), class = "data.frame")

df<- setDT(strs)[, paste0('colids_',seq_along(strs)) := 
    lapply(.SD, function(x) toString(which(colSums(lut == x, na.rm=TRUE) > 0))), 
    by = 1:nrow(strs)][]

然后我收到此错误:

  

df1 == x中的错误:未实施这些类型的比较   另外:警告信息:is.data.frame(x)
  “Ops.data.frame”的不兼容方法(“Ops.factor”,“==”)

1 个答案:

答案 0 :(得分:4)

使用colSumswhichtoStringapply组合的基础R的可能解决方案:

strs$colids <- apply(strs, 1, function(x) toString(which(colSums(lut == x, na.rm=TRUE) > 0)))

给出:

> strs
  strings  colids
1  O75663    1, 3
2  O95400    1, 3
3  O95433    1, 3
4  O95456 2, 3, 4
5  O95670 2, 3, 4
6  O95801       4
7  P00352       4
8  P00492        

要查看每个部分的作用,首先查看lut == 'O75663'的输出,它将为您提供TRUE/FALSE表。通过将其包裹在colSums中,您可以将TRUE/FALSE加起来。 0表示该列中该字符串不匹配,大于零的数字表示存在一个或多个匹配项。使用which,您可以获得列索引,并将其包装在toString中,您将获得具有匹配列索引的字符值。

此方法也可以使用data.tabledplyr

来实施
library(data.table)
setDT(strs)[, colids := toString(which(colSums(lut == strings, na.rm=TRUE) > 0)), by = 1:nrow(strs)][]

library(dplyr)
strs %>% rowwise() %>% mutate(colids = toString(which(colSums(lut == strings, na.rm=TRUE) > 0)))

回复您的评论:strs data.table中多列的示例:

# create an extra strings column
set.seed(1)
strs$strings2 <- sample(strs$strings)

# create two 'colids' columns
library(data.table)
setDT(strs)[, c('colids1','colids2') := lapply(.SD, function(x) toString(which(colSums(lut == x, na.rm=TRUE) > 0))), by = 1:nrow(strs)][]

给出:

   strings strings2 colids1 colids2
1:  O75663   O95433    1, 3    1, 3
2:  O95400   P00492    1, 3        
3:  O95433   O95456    1, 3 2, 3, 4
4:  O95456   O95670 2, 3, 4 2, 3, 4
5:  O95670   O75663 2, 3, 4    1, 3
6:  O95801   P00352       4       4
7:  P00352   O95400       4    1, 3
8:  P00492   O95801               4

使用过的数据

lut <- structure(list(V1 = c("O75663", "O95400", "O95433", NA, NA), 
                      V2 = c("O95456", "O95670", NA, NA, NA), 
                      V3 = c("O75663", "O95400", "O95433", "O95456", "O95670"), 
                      V4 = c("O95456", "O95670", "O95801", "P00352", NA)), 
                 .Names = c("V1", "V2", "V3", "V4"), class = "data.frame", row.names = c(NA, -5L))

strs <- structure(list(strings = c("O75663", "O95400", "O95433", "O95456", "O95670", "O95801", "P00352", "P00492")), 
                  .Names = "strings", class = "data.frame", row.names = c(NA, -8L))

关于您添加到问题中的扩展示例:您获得该错误的原因是您尝试将因子变量与字符变量进行比较。查看sapply(strs,class)sapply(lut,class)之间的输出差异:

> sapply(strs,class)
strings1 strings2 strings3 strings4 strings5 
"factor" "factor" "factor" "factor" "factor" 
> sapply(lut,class)
         V1          V2          V3          V4          V5          V6          V7          V8 
"character" "character" "character" "character" "character" "character" "character" "character" 

因此,有必要先将factor转换为character,然后再进行比较。以下代码:

library(data.table)
setDT(strs)[, lapply(.SD, as.character)
            ][, paste0('colids.',seq_along(strs)) := lapply(.SD, function(x) toString(which(colSums(lut == x, na.rm=TRUE) > 0))), 
              by = 1:nrow(strs)][]

现在提供正确的输出:

   strings1 strings2 strings3 strings4 strings5         colids.1         colids.2         colids.3         colids.4         colids.5
1:   O75663   O95456   O95456   O95400   P00492       1, 3, 5, 7 2, 3, 4, 6, 7, 8 2, 3, 4, 6, 7, 8       1, 3, 5, 7                 
2:   O95400   O75663   O95801   P00492   O95400       1, 3, 5, 7       1, 3, 5, 7             4, 8                        1, 3, 5, 7
3:   O95433   P00492   P00352   O95456   P00352       1, 3, 5, 7                              4, 8 2, 3, 4, 6, 7, 8             4, 8
4:   O95456   P00352   P00492   O95801   O75663 2, 3, 4, 6, 7, 8             4, 8                              4, 8       1, 3, 5, 7
5:   O95670   O95433   O75663            O95433 2, 3, 4, 6, 7, 8       1, 3, 5, 7       1, 3, 5, 7                        1, 3, 5, 7
6:   O95801            O95400            O95801             4, 8                        1, 3, 5, 7                              4, 8
7:                     O95670            O95670                                   2, 3, 4, 6, 7, 8                  2, 3, 4, 6, 7, 8
8:                                       O95456                                                                     2, 3, 4, 6, 7, 8

使用过的数据扩展示例

strs <- structure(list(strings1 = structure(c(2L, 3L, 4L, 5L, 6L, 7L, 1L, 1L), .Label = c("", "O75663", "O95400", "O95433", "O95456", "O95670", "O95801"), class = "factor"), 
                       strings2 = structure(c(4L, 2L, 6L, 5L, 3L, 1L, 1L, 1L), .Label = c("", "O75663", "O95433", "O95456", "P00352", "P00492"), class = "factor"), 
                       strings3 = structure(c(4L, 6L, 7L, 8L, 2L, 3L, 5L, 1L), .Label = c("", "O75663", "O95400", "O95456", "O95670", "O95801", "P00352", "P00492"), class = "factor"), 
                       strings4 = structure(c(2L, 5L, 3L, 4L, 1L, 1L, 1L, 1L), .Label = c("", "O95400", "O95456", "O95801", "P00492"), class = "factor"), 
                       strings5 = structure(c(8L, 2L, 7L, 1L, 3L, 6L, 5L, 4L), .Label = c("O75663", "O95400", "O95433", "O95456", "O95670", "O95801", "P00352", "P00492"), class = "factor")), 
                  .Names = c("strings1", "strings2", "strings3", "strings4", "strings5"), class = "data.frame", row.names = c(NA, -8L))

lut <- structure(list(V1 = c("O75663", "O95400", "O95433", NA, NA), 
                      V2 = c("O95456", "O95670", NA, NA, NA), 
                      V3 = c("O75663", "O95400", "O95433", "O95456", "O95670"), 
                      V4 = c("O95456", "O95670", "O95801", "P00352", NA), 
                      V5 = c("O75663", "O95400", "O95433", NA, NA), 
                      V6 = c("O95456", "O95670", NA, NA, NA), 
                      V7 = c("O75663", "O95400", "O95433", "O95456", "O95670"), 
                      V8 = c("O95456", "O95670", "O95801", "P00352", NA)), 
                 .Names = c("V1", "V2", "V3", "V4", "V5", "V6", "V7", "V8"), row.names = c(NA, -5L), class = "data.frame")