如何根据其单元格具有多个以逗号分隔的值的观察来对 r 中的数据帧进行子集化?

How to subset a dataframe in r based on an observation whose cell has more than one value separated by commas?

我对 R 和一般编程还很陌生,所以请多多包涵。

我有一个非常大的数据集(超过 100,000 个观察值)。我想根据一个特定列的值对该数据集进行子集化。我面临的问题是,我感兴趣的列中的各个单元格可以同时采用多个值,所有值都用逗号分隔。例如假设我有一个数据集 'm':

row1<-c('1','Jon,Ryan,Lilly','Soccer','3')
row2<-c('2','Carol,Ben,Peter','Soccer','6')
row3<-c('3','Ben,Carol,Billy','Soccer','5')
row4<-c('4','Felix,Jon,Casper','Soccer','3')

m<-rbind(row1,row2,row3,row4)
colnames(m)<-c('ID','Name','Event','Duration')
rownames(m)<-c(1,2,3,4)

print(m)

  ID    Name     Event    Duration
1 "1" "Jon,Ryan, Lilly"    "Soccer" "3"     
2 "2" "Carol, Ben, Peter"  "Soccer" "6"     
3 "3" "Ben, Carol, Billy"  "Soccer" "5"     
4 "4" "Felix, Jon, Casper" "Soccer" "3" 

如何对 'm' 进行子集化,使得 R 仅 returns 个名称列等于 'Jon' 的观察值。我试过了

subset(data, Name=='Jon') 

但只有 returns 个字段,其中 'Jon' 是唯一列出的名称。我知道使用 reshape 中的 colsplit 可以从这些不同的元素创建一个新列,但有些单元格具有不同数量的列,有些单元格有超过 10 个元素,并且所有单元格中总共有超过 100 个不同的唯一名称。他们是 R 中的一个命令,可以基于名称字符串的 'subset' 进行子集化吗?像 subset 函数一样简单的东西,但它也查询字符串的一部分。预先感谢大家的帮助!

您要搜索的姓名在姓名列表中的位置有 4 种不同的可能性:

  1. 它是名字列表中唯一的名字
  2. 它是名字列表中几个名字中的第一个
  3. 它是名字列表中几个名字中的最后一个
  4. 它位于名称列表的中间位置

因此,您可以将 grepl 与匹配字符串一起使用,如果它位于任何这些特定位置:

Name  <-  c("Jon,Ryan, Lilly",
            "Carol, Ben, Peter",
            "Ben, Carol, Billy",
            "Felix, Jon, Casper")

grepl('(^\s*Jon,)|(,\s*Jon,)|(,\s*Jon\s*$)|(^\s*Jon\s*$)',Name)
#> [1]  TRUE FALSE FALSE  TRUE

你可以这样概括:

includesName <- function(name,x)
    grepl(paste0('(^\s*',name,',)|(,\s*',name,',)|(,\s*',name,'\s*$)|(^\s*',name,'\s*$)'),
          x)
includesName('Jon',Name)
#> [1]  TRUE FALSE FALSE  TRUE

'\s'的使用是允许白色 space 可以包含在名称之间或列表的末尾(特别是如果这些数据存储在具有固定宽度字符的数据库中列,或者在手动输入的情况下)。

显式匹配每个场景的原因是(而不是 "(Jon$)|(Jon,)" 是为了匹配全名,这样你就不会无意中匹配到 "Ron Jon"。

您可以使用此代码和 return 布尔值搜索 Jon。

m.df <- as.data.frame(m)
m.df$Name <- as.character(m.df$Name)
m.df$new <- str_detect(m.df$Name, "Jon")

> m.df
  ID             Name  Event Duration   new
1  1   Jon,Ryan,Lilly Soccer        3  TRUE
2  2  Carol,Ben,Peter Soccer        6 FALSE
3  3  Ben,Carol,Billy Soccer        5 FALSE
4  4 Felix,Jon,Casper Soccer        3  TRUE

正在回复评论

这是搜索多个名称列的技巧。组合任意多的列来搜索,然后在组合列上使用相同的代码。

假设您还有一个名为 NameTwo 的列 -

m.df$combo <- paste(m.df$Name, m.df$NameTwo, sep = ",")
m.df$new <- str_detect(m.df$combo, "Jon")

这对 dplyr 来说是一项艰巨的任务,尤其是考虑到您的真实数据的大小。我为你的 m 创建了一个 tbl_df,它基本上是一个 data.frame。我包括第二个基于名称的变量,因为你问过这个。我创建了一个自定义函数来搜索字符串 Jon。然后使用 mutate_each() 在名称变量中搜索,然后将结果过滤为 return 仅匹配的行。

library(dplyr)
library(stringr)

m <- data_frame(Name1 = c('Jon,Ryan,Lilly', 'Carol,Ben,Peter',
                         'Ben,Carol,Billy', 'Felix,Jon,Casper'),
                Name2 = c('Susie,Jenny,Katy', 'Nigel,Ian,Jon',
                          'Nigel, Jenny', 'Ryan, Lilly, Ben'),
                Event = 'Soccer',
                Duration = c(3, 6, 5, 3))
m
# Source: local data frame [4 x 4]

#              Name1            Name2  Event Duration
# 1   Jon,Ryan,Lilly Susie,Jenny,Katy Soccer        3
# 2  Carol,Ben,Peter    Nigel,Ian,Jon Soccer        6
# 3  Ben,Carol,Billy     Nigel, Jenny Soccer        5
# 4 Felix,Jon,Casper Ryan, Lilly, Ben Soccer        3

jon_fun <- function(x) str_detect(x, '\bJon\b')

m %>%
  mutate_each(funs(jon_fun), jon1 = Name1, jon2 = Name2) %>%
  filter(jon1 | jon2) %>%
  select(-starts_with('jon'))
# Source: local data frame [3 x 4]

#              Name1            Name2  Event Duration
# 1   Jon,Ryan,Lilly Susie,Jenny,Katy Soccer        3
# 2  Carol,Ben,Peter    Nigel,Ian,Jon Soccer        6
# 3 Felix,Jon,Casper Ryan, Lilly, Ben Soccer        3