根据数据框中的特定条件应用计算

Apply calculations based on certain conditions in a data frame

我有以下数据框:

Source  mean1   SD  median  range_min   range_max   IQR_25  IQR_75  
1       1.5     0.2 3       NA          NA          NA      NA      
2       NA      NA  2       1           5           1.5     4       
3       NA      NA  4       2           7           NA      NA      

我想根据特定条件将 mean2FLAG 列添加到数据框中。条件如下:

1) 如果存在 mean1sd 则将相同的值复制到 mean2 列中并给它 FLAG ==1

2) 如果 mean1sdNAmedian:IQR_75 存在则将 mean2 的值等于 20 并给它一个 FLAG==2。注意:值 20 是任意的。我将用一个等式来代替,但这是为了让这里的问题更容易。

3) 如果如果 mean1sdNAmedian, RANGE_min, RANGE_max 存在则将 mean2 的值等于 30 并给它一个FLAG==3.

结果应如下所示:

Source  mean1   SD  median  range_min   range_max   IQR_25  IQR_75  mean2   FLAG
1       1.5     0.2 3       NA          NA          NA      NA      1.5     1
2       NA      NA  2       1           5           1.5     4       20      2
3       NA      NA  4       2           7           NA      NA      30      3

我尝试了以下方法,但使用起来不太顺利:

df$mean2 <- with(df, (is.na(mean1)==F&(is.na(SD)==F))*mean1+ (is.na(mean1)==T & is.na(SD)==T & is.na(median)==F &
                        is.na(range_min)==F & is.na(range_max)==F & is.na(IQR_25)==F &
                        is.na(IQR_75)==F)*20)

我会请你帮助实现我的目标,这样我就可以将它应用到我的大数据集上。

我们可以根据指定列中的 NA 元素创建几个逻辑索引。如果 'mean1' 和 'SD' 都不是 NA,'indx' 给出 TRUE,如果 'median:IQR_75' 列的行中没有 NA 值,'indx2' 将为 TRUE我们正在使用 NA 元素的 rowSums。同样,'indx3' 为列 'median:range_max'.

的非 NA 元素提供 TRUE
 indx <- rowSums(!is.na(df1[c('mean1', 'SD')]))==2
 indx2 <- !rowSums(is.na(df1[4:ncol(df1)]))
 indx3 <- !rowSums(is.na(df1[4:6]))

现在我们可以通过算术运算创建一个数字索引来创建一个唯一索引('indx4'),它可以用来填充值1.5、30、20或1:3。

 indx4 <- as.numeric(factor(1+2*indx+4*indx2+8*indx3))
  c(1.5, 30, 20)[indx4]
 #[1]  1.5 20.0 30.0
 c(1,3,2)[indx4]
 #[1] 1 2 3

或者我们使用嵌套 ifelse

 df1$mean2 <- ifelse(indx, 1.5, ifelse(indx2, 20, ifelse(indx3, 30, NA)))
 df1$mean2
 #[1]  1.5 20.0 30.0

 df1$FLAG <- ifelse(indx, 1, ifelse(indx2, 2, ifelse(indx3, 3, NA)))
 df1$FLAG
 # [1] 1 2 3

df1
#   Source mean1  SD median range_min range_max IQR_25 IQR_75 mean2 FLAG
#1      1   1.5 0.2      3        NA        NA     NA     NA   1.5    1
#2      2    NA  NA      2         1         5    1.5      4  20.0    2
#3      3    NA  NA      4         2         7     NA     NA  30.0    3

数据

df1 <- structure(list(Source = 1:3, mean1 = c(1.5, NA, NA), SD = c(0.2, 
 NA, NA), median = c(3L, 2L, 4L), range_min = c(NA, 1L, 2L),
 range_max = c(NA, 
 5L, 7L), IQR_25 = c(NA, 1.5, NA), IQR_75 = c(NA, 4L, NA)),
 .Names = c("Source", 
 "mean1", "SD", "median", "range_min", "range_max", "IQR_25", 
 "IQR_75"), class = "data.frame", row.names = c(NA, -3L))

使用 data.table 包,您可以按如下方式进行:

library(data.table)
setDT(df)[!is.na(mean1) & !is.na(SD), `:=` (mean2 = mean1, Flag = 1)
          ][is.na(mean1) & is.na(SD) & complete.cases(median,range_min,range_max,IQR_25,IQR_75),
            `:=` (mean2 = 20, Flag = 2)
            ][is.na(mean1) & is.na(SD) & complete.cases(median,range_min,range_max) & is.na(IQR_25) & is.na(IQR_75),
              `:=` (mean2 = 30, Flag = 3)]

这给出:

> df
   Source mean1  SD median range_min range_max IQR_25 IQR_75 mean2 Flag
1:      1   1.5 0.2      3        NA        NA     NA     NA   1.5    1
2:      2    NA  NA      2         1         5    1.5      4  20.0    2
3:      3    NA  NA      4         2         7     NA     NA  30.0    3

或者,您可以预先为您的多个条件创建索引。这将提供更清晰的 data.table 语法:

indx1 <- complete.cases(df[c("mean1", "SD")])
indx2 <- complete.cases(df[c("median","range_min","range_max","IQR_25","IQR_75")])
indx3 <- !complete.cases(df[c("IQR_25","IQR_75")]) & complete.cases(df[c("median","range_min","range_max")])

library(data.table)
setDT(df)[indx1, `:=` (mean2 = mean1, Flag = 1)
          ][!indx1 & indx2, `:=` (mean2 = 20, Flag = 2)
            ][!indx1 & indx3, `:=` (mean2 = 30, Flag = 3)]

试试这个:

df$mean2 = NA
df$FLAG = NA

ind1 = complete.cases(df[, c("mean1", "SD")])
ind2 = complete.cases(df[, c("median", "range_min", "range_max", "IQR_25", "IQR_75")])
ind3 = complete.cases(df[, c("median", "range_min", "range_max")])

df$mean2[ind1] = df$mean1[ind1]
df$mean2[!ind1 & ind2] = 20 
df$mean2[!ind1 & !ind2 & ind3] = 30

df$FLAG[ind1] = 1
df$FLAG[!ind1 & ind2] = 2 
df$FLAG[!ind1 & !ind2 & ind3] = 3