R在data.table中填充部分NA

时间:2014-07-17 19:15:54

标签: r data.table

我有以下data.table:

dt <- data.table(date=rep(c(2014,2013), each=4), price=c(3.14, 1.45, 3.4 ,5.1, 1, 2.3, 2.79, 3), brand=rep(c("Mercedes", "Audi"), each=4), num=c(3,6,7,8,3,5,9,12), seller=rep(c("gregory", "dan"), each=4))

导致:

   date price    brand num  seller
1: 2013  1.00     Audi   3     dan
2: 2013  2.30     Audi   5     dan
3: 2013  2.79     Audi   9     dan
4: 2013  3.00     Audi  12     dan
5: 2014  3.14 Mercedes   3 gregory
6: 2014  1.45 Mercedes   6 gregory
7: 2014  3.40 Mercedes   7 gregory
8: 2014  5.10 Mercedes   8 gregory

我的目标是:

    date num price    brand  seller
 1: 2013   3  1.00     Audi     dan
 2: 2013   5  2.30     Audi     dan
 3: 2013   6    NA     Audi     dan
 4: 2013   7    NA     Audi     dan
 5: 2013   8    NA     Audi     dan
 6: 2013   9  2.79     Audi     dan
 7: 2013  12  3.00     Audi     dan
 8: 2014   3  3.14 Mercedes gregory
 9: 2014   5    NA Mercedes gregory
10: 2014   6  1.45 Mercedes gregory
11: 2014   7  3.40 Mercedes gregory
12: 2014   8  5.10 Mercedes gregory
13: 2014   9    NA Mercedes gregory
14: 2014  12    NA Mercedes gregory

我首先为每个日期添加缺失数字的行:

setkey(dt, date, num)
dtt<-dt[CJ(unique(date), unique(dt[,num]))]

实现第一步:

    date num price    brand  seller
 1: 2013   3  1.00     Audi     dan
 2: 2013   5  2.30     Audi     dan
 3: 2013   6    NA       NA      NA
 4: 2013   7    NA       NA      NA
 5: 2013   8    NA       NA      NA
 6: 2013   9  2.79     Audi     dan
 7: 2013  12  3.00     Audi     dan
 8: 2014   3  3.14 Mercedes gregory
 9: 2014   5    NA       NA      NA
10: 2014   6  1.45 Mercedes gregory
11: 2014   7  3.40 Mercedes gregory
12: 2014   8  5.10 Mercedes gregory
13: 2014   9    NA       NA      NA
14: 2014  12    NA       NA      NA

然后:

dtt[date==2013, c("brand","seller"):=list("Audi","dan")]
dtt[date==2014, c("brand","seller"):=list("Mercedes","gregory")]

给出想要的结果。

然而:

1 - 最后一段代码很糟糕。

2 - 我想制作一个通用函数(或连接),因为我有很多不同的日期和列来替换/保留我的真实数据中的NA。表。

看起来很简单,但我被困住了!

2 个答案:

答案 0 :(得分:2)

怎么样:

require(data.table) ## 1.9.2
setkey(dt, num)
nums = unique(dt$num)
dt[, list(price=.SD[J(nums)]$price, brand=brand[1L], 
          num=nums, seller=seller[1L]), by=date]
#     date price    brand num  seller
#  1: 2014  3.14 Mercedes   3 gregory
#  2: 2014    NA Mercedes   5 gregory
#  3: 2014  1.45 Mercedes   6 gregory
#  4: 2014  3.40 Mercedes   7 gregory
#  5: 2014  5.10 Mercedes   8 gregory
#  6: 2014    NA Mercedes   9 gregory
#  7: 2014    NA Mercedes  12 gregory
#  8: 2013  1.00     Audi   3     dan
#  9: 2013  2.30     Audi   5     dan
# 10: 2013    NA     Audi   6     dan
# 11: 2013    NA     Audi   7     dan
# 12: 2013    NA     Audi   8     dan
# 13: 2013  2.79     Audi   9     dan
# 14: 2013  3.00     Audi  12     dan

或者:

dt[, c(.SD[J(nums), list(price=price)], brand=brand[1L], 
           seller=seller[1L]), by=date]

其中列的顺序不同。


1.9.3中,这将更有效(在语法和速度方面),因为我们不必加入并返回所有列:

## 1.9.3
dt[, list(price=.SD[J(nums), price], brand=brand[1L], 
          num=nums, seller=seller[1L]), by=date]

.SD[J(nums), price]将导致向量,而不是先前版本中的data.table,并且不会执行隐式(by-without-by),因此也会更快。

详细了解v1.9.3 here实施的新FR(第1点和第2点)下的内容。

HTH

答案 1 :(得分:2)

您可以使用roll参数填充NA的最近值。问题是,这也将填补price,但这很容易解决:

setkey(dt, date, num)

dt[CJ(unique(date), unique(num)), roll = 'nearest'][!dt, price := NA][]
#    date price    brand num  seller
# 1: 2013  1.00     Audi   3     dan
# 2: 2013  2.30     Audi   5     dan
# 3: 2013    NA     Audi   6     dan
# 4: 2013    NA     Audi   7     dan
# 5: 2013    NA     Audi   8     dan
# 6: 2013  2.79     Audi   9     dan
# 7: 2013  3.00     Audi  12     dan
# 8: 2014  3.14 Mercedes   3 gregory
# 9: 2014    NA Mercedes   5 gregory
#10: 2014  1.45 Mercedes   6 gregory
#11: 2014  3.40 Mercedes   7 gregory
#12: 2014  5.10 Mercedes   8 gregory
#13: 2014    NA Mercedes   9 gregory
#14: 2014    NA Mercedes  12 gregory

我认为这应该比.SD[...]解决方案快得多。