根据 R 列中的部分匹配创建新变量

Posted

技术标签:

【中文标题】根据 R 列中的部分匹配创建新变量【英文标题】:Create new variable based on partial matching in column R 【发布时间】:2020-04-01 17:48:49 【问题描述】:

我正在尝试根据以下数据在 data.frame 中创建一个新变量:

df <- structure(list(id = c(123L, 123L, 332L, 332L, 332L, 100L, 100L, 
113L, 113L, 113L, 113L, 551L, 551L), icpc = c("D95", "F85", "A01", 
"A04", "K20", "B10", "A04", "T08", "P28", "D95", "A04", "B12", 
"D95"), icpc2 = c("F15", "", "", "", "", "", "", "", "", "A01", 
"", "A01", ""), reg.date = c("19JUN2015", "15AUG2016", "16MAR2010", 
"20JAN2018", "20FEB2017", "01JUN2017", "11JAN2008", "18MAR2018", 
"19JAN2017", "16JAN2013", "01MAY2009", "03APR2011", "09MAY2015"
)), class = "data.frame", row.names = c(NA, -13L))

我已经为新列condit 使用了以下代码:

library(data.table)

cond1 <- c("D95", "A01")
setDT(df)[, condit := ifelse(any(icpc %in% cond1 | icpc2 %in% cond1), "yes","no"), by=id]
df

但是,我正在处理一个大型数据集 (>4000 万),并且还想根据 icpcicpc2 中的字母进行分类。

我的目标是添加一个新列,其中包含yesno 的字母A(因此,A01A04A50 等)列icpcicpc2。我还希望所有具有相同id 的列在新列condit2 中都有yes

我正在尝试以下方法:

df2 <- setDT(df)[, condit2 := ifelse
                            (any(icpc %in% pmatch("K", df) | icpc2 %in% pmatch("K", df)), "yes","no"), by = PATNR]
head(df2)

这一直在运行......(我想,无论如何,df 太面包了,如果应该是 df$icpcdf$icpc2?)

比以下检查pmatch是否合适:

condit2 <- pmatch("K")

然后看着完全不同的东西:

library(sqldf)
condit2 <- sqldf("df$icpc | df$icpc2, '%K%'")

这应该会产生以下数据框:

    id  icpc icpc2 reg.date    condit2
 1: 123  D95   F15 19JUN2015    no
 2: 123  F85       15AUG2016    no
 3: 332  A01       16MAR2010    yes
 4: 332  A04       20JAN2018    yes
 5: 332  K20       20FEB2017    yes
 6: 100  B10       01JUN2017    yes
 7: 100  A04       11JAN2008    yes
 8: 113  T08       18MAR2018    yes
 9: 113  P28       19JAN2017    yes
10: 113  D95   A01 16JAN2013    yes
11: 113  A04       01MAY2009    yes
12: 551  B12   A01 03APR2011    yes
13: 551  D95       09MAY2015    yes

谁能给个提示?谢谢!!

【问题讨论】:

【参考方案1】:
setDT(df)

to_check <- 'A'

df[, condit2 := fifelse(any(grepl(to_check, icpc) | grepl(to_check, icpc2)),
                        'yes', 'no'), 
   by = id]

df
#      id icpc icpc2  reg.date condit2
#  1: 123  D95   F15 19JUN2015      no
#  2: 123  F85       15AUG2016      no
#  3: 332  A01       16MAR2010     yes
#  4: 332  A04       20JAN2018     yes
#  5: 332  K20       20FEB2017     yes
#  6: 100  B10       01JUN2017     yes
#  7: 100  A04       11JAN2008     yes
#  8: 113  T08       18MAR2018     yes
#  9: 113  P28       19JAN2017     yes
# 10: 113  D95   A01 16JAN2013     yes
# 11: 113  A04       01MAY2009     yes
# 12: 551  B12   A01 03APR2011     yes
# 13: 551  D95       09MAY2015     yes

如果,而不是只有两列 icpcicpc2,你有一堆,不想为每一个都输入 grepl 代码,这里是带有 .SDcols 的版本,它给出了同样的结果。

df[, condit2 := fifelse(any(Reduce('|', lapply(.SD, grepl, patt = to_check))),
                        'yes', 'no'), 
   by = id, .SDcols = patterns('icpc')]

【讨论】:

这是针对列,而不是列中的值,对吧? 它正在检查列值以查看它们是否包含“A” 太好了,我现在看到了。为选择列提供额外的选项。超好的。谢谢! 顺便说一句,fifelse 应该是 ifelse fifelse 是一个 data.table 函数,类似于 ifelse,但速度更快(因此前面有 f)【参考方案2】:

使用dplyr,可以通过以下方法完成: group_by(id)paste 将感兴趣的两列放在一起,使用sumgrepl 检查连接的字符串中是否至少出现了一个A

library(dplyr)
df %>% 
  group_by(id) %>% 
  mutate(condit2 = case_when(sum(grep("A", paste(icpc, icpc2))) > 0 ~ "yes",
                             TRUE ~ "no")) %>% 
  ungroup()


      id icpc  icpc2 reg.date  condit2
   <int> <chr> <chr> <chr>     <chr>  
 1   123 D95   "F15" 19JUN2015 no     
 2   123 F85   ""    15AUG2016 no     
 3   332 A01   ""    16MAR2010 yes    
 4   332 A04   ""    20JAN2018 yes    
 5   332 K20   ""    20FEB2017 yes    
 6   100 B10   ""    01JUN2017 yes    
 7   100 A04   ""    11JAN2008 yes    
 8   113 T08   ""    18MAR2018 yes    
 9   113 P28   ""    19JAN2017 yes    
10   113 D95   "A01" 16JAN2013 yes    
11   113 A04   ""    01MAY2009 yes    
12   551 B12   "A01" 03APR2011 yes    
13   551 D95   ""    09MAY2015 yes    

【讨论】:

以上是关于根据 R 列中的部分匹配创建新变量的主要内容,如果未能解决你的问题,请参考以下文章

根据与另一列的部分匹配创建新列

在 Shiny 中使用部分 textInput 作为 R 中的变量

如何根据一个数据帧中的列值和R中另一个数据帧的列标题名称有条件地创建新列

根据条件验证R中两个数据框之间的列中的值

根据两列中的匹配值为日期差异创建条件列

使用while循环根据R中的重复值创建一个新变量