R根据列值编辑数据框

R editing dataframe based on column value

假设我有一个 table 大约 100 万行,格式如下:

id  paid_2000  paid_2001  paid_2002  paid_2003  censor_yr
1   10         20         10         20         2001
2   15         25         15         15         2003

在付费年份大于或等于审查年份的情况下,将每个观测值设置为 NA 的有效方法是什么?特别是,我希望 table 看起来像这样:

id  paid_2000  paid_2001  paid_2002  paid_2003  censor_yr
1   10         NA         NA         NA         2001
2   15         25         15         NA         2003

我们为 'paid' ('pi') 的列创建索引,使用 'pi' 对列进行子集化,通过比较列中的年份子字符串创建逻辑值矩阵'paid' 列的名称与 'censor_yr' 列的名称并将其分配给 NA。

pi <- grep("paid", names(df1))
df1[pi][matrix(as.numeric(sub(".*_", "", names(df1)[pi]))[col(df1[pi])] >=
                       df1$censor_yr, nrow=2)] <- NA
df1
#   id paid_2000 paid_2001 paid_2002 paid_2003 censor_yr
#1  1        10        NA        NA        NA      2001
#2  2        15        25        15        NA      2003

或者我们可以在 data.table set 中执行此操作,这样效率会更高。从'paid'列名的names中获取年份子串,转换为data.tablesetDT(df1)),循环遍历'pi'和[=13中的列=] 满足'i'.

条件的NA值
library(data.table)
nm1 <- as.numeric(sub(".*_", "", names(df1)[pi]))
setDT(df1)
for(j in seq_along(pi)){
   set(df1, i = which(nm1[j] >= df1$censor_yr), j= pi[j], value = NA)
}

使用dplyr

library(dplyr)
df %>%
  gather(paid_yr, value, grep("paid", names(.))) %>%
  mutate(value = ifelse(as.numeric(gsub(".*_", "", paid_yr)) >= censor_yr, 
                        NA, value)) %>%
  spread(paid_yr, value)

在底部扔一个 %>% select 链子以将 censor_yr 移回末端。

如果您愿意,可以解释它是如何工作的。可能比 akrun 的答案更容易阅读,也可能不更容易阅读。