R 使用data.table包的笛卡尔积
使用R中的data.table包,我尝试使用merge方法创建两个data.tables的笛卡尔乘积,就像在BaseR中一样 在以下工作的基础上:R 使用data.table包的笛卡尔积,r,data.table,R,Data.table,使用R中的data.table包,我尝试使用merge方法创建两个data.tables的笛卡尔乘积,就像在BaseR中一样 在以下工作的基础上: #assume this order data orders <- data.frame(date = as.POSIXct(c('2012-08-28','2012-08-29','2012-09-01')), first.name = as.character(c('John','George','
#assume this order data
orders <- data.frame(date = as.POSIXct(c('2012-08-28','2012-08-29','2012-09-01')),
first.name = as.character(c('John','George','Henry')),
last.name = as.character(c('Doe','Smith','Smith')),
qty = c(10,50,6))
#and these dates
dates <- data.frame(date = seq(from = as.POSIXct('2012-08-28'),
to = as.POSIXct('2012-09-07'), by = 'day'))
#get the unique customers
cust<-unique(orders[,c('first.name','last.name')])
#using merge from base R, get the cartesian product
merge(dates, cust, by = integer(0))
我希望结果反映所有日期的所有客户名称,就像在base中一样,但要以数据表为中心。这可能吗?merge.data.table(x,y)
是一个方便的函数,它包装了对x[y]
的调用,因此合并需要基于data.table
中的列。(这就是错误消息试图告诉您的内容)
一种解决方法是向两个data.tables添加一个伪列,其唯一目的是使合并成为可能:
## Add a column "k", and append it to each data.table's vector of keyed columns.
setkeyv(cust.dt[,k:=1], c(key(cust.dt), "k"))
setkeyv(dates.dt[,k:=1], c(key(dates.dt), "k"))
## Merge and then remove the dummy column
res <- merge(dates.dt, cust.dt, by="k")
head(res[,k:=NULL])
# date first.name last.name
# 1: 2012-08-28 George Smith
# 2: 2012-08-28 Henry Smith
# 3: 2012-08-28 John Doe
# 4: 2012-08-29 George Smith
# 5: 2012-08-29 Henry Smith
# 6: 2012-08-29 John Doe
## Maybe also clean up cust.dt and dates.dt
# cust.dt[,k:=NULL]
# dates.dt[,k=NULL]
##添加列“k”,并将其附加到每个数据。表的键控列向量。
setkeyv(cust.dt[,k:=1],c(key(cust.dt),“k”))
setkeyv(dates.dt[,k:=1],c(key(dates.dt),“k”))
##合并然后删除虚拟列
res如果从数据帧中的第一个和最后一个构建全名,则可以使用CJ
(交叉连接)。您不能使用所有三个向量,因为将有99个项目
> nrow(CJ(dates$date, cust$first.name, cust$last.name ) )
[1] 99
这将返回一个data.table对象:
> CJ(dates$date,paste(cust$first.name, cust$last.name) )
V1 V2
1: 2012-08-28 George Smith
2: 2012-08-28 Henry Smith
3: 2012-08-28 John Doe
4: 2012-08-29 George Smith
5: 2012-08-29 Henry Smith
6: 2012-08-29 John Doe
7: 2012-08-30 George Smith
8: 2012-08-30 Henry Smith
9: 2012-08-30 John Doe
10: 2012-08-31 John Doe
11: 2012-08-31 George Smith
12: 2012-08-31 Henry Smith
13: 2012-09-01 John Doe
14: 2012-09-01 George Smith
15: 2012-09-01 Henry Smith
16: 2012-09-02 George Smith
17: 2012-09-02 Henry Smith
18: 2012-09-02 John Doe
19: 2012-09-03 Henry Smith
20: 2012-09-03 John Doe
21: 2012-09-03 George Smith
22: 2012-09-04 Henry Smith
23: 2012-09-04 John Doe
24: 2012-09-04 George Smith
25: 2012-09-05 George Smith
26: 2012-09-05 Henry Smith
27: 2012-09-05 John Doe
28: 2012-09-06 George Smith
29: 2012-09-06 Henry Smith
30: 2012-09-06 John Doe
31: 2012-09-07 George Smith
32: 2012-09-07 Henry Smith
33: 2012-09-07 John Doe
V1 V2
来自@JoshO'Brien的解决方案使用了merge
,但下面是一个类似的替代方案,没有(AFAIK)
如果我正确理解了?data.table::merge
中的文档,X[Y]
应该比data.table::merge(X,Y)
稍快一些(从1.8.7版开始)。为了解决这个问题,参考FAQ 2.12,但是FAQ有点混乱。首先,正确的参考值应该是1.12,而不是2.12。并且它们不表示它们是引用merge的基本版本还是data.table one,或者两者都引用。因此,这可能最终成为一个看起来更混乱的解决方案,或者它可能更快。
[编辑自Matthew]谢谢:现在在v1.8.7中有所改进(?merge.data.table
,FAQ 1.12和新增的FAQ 2.24)
DT_ordersOk,CJ是我一直在寻找的,但我认为唯一的id字段更适合我的实际情况,而不是串联名称。谢谢+非常好@ZachWaite——借用了DWin的想法,您还可以尝试合并(CJ(date=dates$date,first.name=cust$first.name),cust,“first.name”)
,然后您可以轻松地对列重新排序,如果您愿意的话。谢谢。现在提出改进?合并和常见问题解答,链接返回此处。
## Add a column "k", and append it to each data.table's vector of keyed columns.
setkeyv(cust.dt[,k:=1], c(key(cust.dt), "k"))
setkeyv(dates.dt[,k:=1], c(key(dates.dt), "k"))
## Merge and then remove the dummy column
res <- merge(dates.dt, cust.dt, by="k")
head(res[,k:=NULL])
# date first.name last.name
# 1: 2012-08-28 George Smith
# 2: 2012-08-28 Henry Smith
# 3: 2012-08-28 John Doe
# 4: 2012-08-29 George Smith
# 5: 2012-08-29 Henry Smith
# 6: 2012-08-29 John Doe
## Maybe also clean up cust.dt and dates.dt
# cust.dt[,k:=NULL]
# dates.dt[,k=NULL]
> nrow(CJ(dates$date, cust$first.name, cust$last.name ) )
[1] 99
> CJ(dates$date,paste(cust$first.name, cust$last.name) )
V1 V2
1: 2012-08-28 George Smith
2: 2012-08-28 Henry Smith
3: 2012-08-28 John Doe
4: 2012-08-29 George Smith
5: 2012-08-29 Henry Smith
6: 2012-08-29 John Doe
7: 2012-08-30 George Smith
8: 2012-08-30 Henry Smith
9: 2012-08-30 John Doe
10: 2012-08-31 John Doe
11: 2012-08-31 George Smith
12: 2012-08-31 Henry Smith
13: 2012-09-01 John Doe
14: 2012-09-01 George Smith
15: 2012-09-01 Henry Smith
16: 2012-09-02 George Smith
17: 2012-09-02 Henry Smith
18: 2012-09-02 John Doe
19: 2012-09-03 Henry Smith
20: 2012-09-03 John Doe
21: 2012-09-03 George Smith
22: 2012-09-04 Henry Smith
23: 2012-09-04 John Doe
24: 2012-09-04 George Smith
25: 2012-09-05 George Smith
26: 2012-09-05 Henry Smith
27: 2012-09-05 John Doe
28: 2012-09-06 George Smith
29: 2012-09-06 Henry Smith
30: 2012-09-06 John Doe
31: 2012-09-07 George Smith
32: 2012-09-07 Henry Smith
33: 2012-09-07 John Doe
V1 V2
DT_orders<-data.table(date=as.POSIXct(c('2012-08-28','2012-08-29','2012-08-29','2012-09-01')),
first.name=as.character(c('John','John','George','Henry')),
last.name=as.character(c('Doe','Doe','Smith','Smith')),
qty=c(10,2,50,6),
key="first.name,last.name")
# Note that I added a second record to the orders table for John Doe, to make sure it could handle duplicate first/last name combinations.
DT_dates<-data.table(date=seq(from=as.POSIXct('2012-08-28'),
to=as.POSIXct('2012-09-07'),by='day'),
key="date")
DT_custdates<-data.table(k=1,unique(DT_dates),key="k")[unique(DT_orders)[,list(k=1,first.name,last.name)]][,k:=NULL]