如何修改R的grep正则,筛选数据框时排除指定列?
R: Subset Data Frame to Include Date and 6M-ending Columns (Excluding Specific Patterns)
问题
我有如下所示的数据框df:
df <- data.frame(date=as.Date(c('2018-01-01', '2018-02-01', '2018-03-01')), rate6M=rnorm(3), oldrate6M=rnorm(3), marketrate6M=rnorm(3), rate12M=rnorm(3), oldrate12M=rnorm(3), marketrate12M=rnorm(3))
我想要创建df的子集df6M,包含date列以及所有以6M结尾的列,但需排除包含oldrate或marketrate的列。目前能筛选出date和所有以6M结尾列的代码如下:
df6M <- df[grep('date|6M$', names(df))]
请问如何修改上述代码,以明确排除包含oldrate或marketrate的列?
注:请勿给出类似df6M <- df[grep('date|^rate6M$', names(df))]的方案,因为实际中我的数据框包含大量以6M结尾的列,我需要明确排除指定列。
解决方案
这里有几种不同的方法可以实现你的需求,既满足批量筛选6M结尾列,又能精准排除指定模式的列:
方法1:Base R 结合两次grep(直观易理解)
先筛选出初始符合条件的列(date或6M结尾),再从中移除包含oldrate或marketrate的列:
# 获取初始匹配的列名 initial_cols <- grep('date|6M$', names(df), value = TRUE) # 找出需要排除的列 exclude_cols <- grep('oldrate|marketrate', initial_cols, value = TRUE) # 取差集得到最终列,生成子集 df6M <- df[setdiff(initial_cols, exclude_cols)]
方法2:Base R 用正则负向预查(简洁写法)
利用Perl风格的正则负向预查,直接匹配符合要求的列名,一步到位:
df6M <- df[grep('date|^(?!oldrate|marketrate).*6M$', names(df), perl = TRUE)]
正则表达式解释:
date:直接匹配date列^(?!oldrate|marketrate).*6M$:匹配以6M结尾,但开头不是oldrate或marketrate的列((?!...)是负向预查,需要开启perl=TRUE来支持)
方法3:逻辑向量组合筛选(可读性拉满)
用逻辑条件组合需求,无需复杂正则,新手友好:
# 条件1:是date列,或者列名以6M结尾 cond1 <- names(df) == 'date' | grepl('6M$', names(df)) # 条件2:列名不包含oldrate或marketrate cond2 <- !grepl('oldrate|marketrate', names(df)) # 同时满足两个条件的列就是我们要的 df6M <- df[cond1 & cond2]
方法4:Tidyverse风格(dplyr包)
如果你习惯用tidyverse工具链,dplyr::select的辅助函数能让代码更简洁直观:
library(dplyr) df6M <- df %>% select(date, ends_with("6M"), -contains("oldrate"), -contains("marketrate"))
这里ends_with("6M")选中所有以6M结尾的列,-contains()则排除包含指定关键词的列,逻辑清晰一目了然。
内容的提问来源于stack exchange,提问作者Gaurav Bansal
相关产品推荐
相关产品推荐

