使用data.table中的lookup替换值

时间:2017-09-21 20:49:24

标签: r data.table

我有一个data.table,如下所示

col1  col2  col3
1      A     23
2      B     20
3      A     23
4      B     0
5      B     20
6      A     0
7      C     10

当col2匹配时,我想用col3的值替换所有0。例如,在这种情况下,row4, col3应替换为20,而row6,col3应替换为23

编辑: 由于row6,col2A,我想要col3对应col2==A

的最常见非零值或唯一非零值(在本例中为23){{1}}

2 个答案:

答案 0 :(得分:2)

OP已澄清他希望将col3中的任何零值替换为每个col2组的最常见非零值。

问题标记为data.table,这里有一些data.table解决方案:

1。与ifelse()

一起更新加入
library(data.table)
# find most frequent non-zero value by group
tmp <- DT[col3 != 0, .N, by = .(col2, col3)][order(N), .(col3 = last(col3)), by = col2]
tmp
   col2 col3
1:    C   10
2:    A   23
3:    B   20
# update on join
DT[tmp, on = .(col2), col3 := ifelse(col3 == 0, i.col3, col3)][]
   col1 col2 col3
1:    1    A   23
2:    2    B   20
3:    3    A   23
4:    4    B   20
5:    5    B   20
6:    6    A   23
7:    7    C   10

2。在没有ifelse()

的情况下更新加入

有一个变体用更复杂的连接替换ifelse()表达式:

tmp <- DT[col3 != 0, .N, by = .(col2, col3)][order(N), last(col3), by = col2][, col3 := 0]
tmp
   col2 V1 col3
1:    C 10    0
2:    A 23    0
3:    B 20    0
DT[tmp, on = .(col2, col3), col3 := V1][]
   col1 col2 col3
1:    1    A   23
2:    2    B   20
3:    3    A   23
4:    4    B   20
5:    5    B   20
6:    6    A   23
7:    7    C   10

3。使用zoo::na.aggregate()raster::modal()

zoo包提供了几种替换NA值的功能。

DT[col3 == 0, col3 := NA][
  # replace NA by modal value (most frequent value) per group
  , col3 := as.integer(zoo::na.aggregate(col3, FUN = raster::modal)), by = col2][]
   col1 col2 col3
1:    1    A   23
2:    2    B   20
3:    3    A   23
4:    4    B   20
5:    5    B   20
6:    6    A   23
7:    7    C   10

请注意,此解决方案可能会在边缘情况下返回前两个解决方案的不同结果:

  • 如果col2组在col3中仅包含零值,则该组中没有最常见的非零值。然后这些零值返回为NA,而其他两个解决方案保持不变。
  • 如果组内有联系,即col3中有两个或多个值同样频繁出现,则不会定义哪个值优先于另一个。

答案 1 :(得分:1)

使用zoo na.locf

library(zoo)
df$col3[df$col3==0]=NA # 1st replace 0 to NA
df=df[order(df$col2,df$col3),] #order df
df$col3=na.locf(df$col3)    
df[order(df$col1),]
  col1 col2 col3
1    1    A   23
2    2    B   20
3    3    A   23
4    4    B   20
5    5    B   20
6    6    A   23
7    7    C   10

或者使用dplyr

df%>%group_by(col2)%>%mutate(col3=ifelse(col3==0,unique(col3[col3!=0]),col3))