19

R で data.table パッケージを使用して、ベース R で行うようにマージ メソッドを使用して、2 つの data.tables のデカルト積を作成しようとしています。

ベースでは、次のように機能します。

#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))

ただし、同じ手法は data.table を使用すると機能せず、次のエラーがスローされます。

"Error in merge.data.table(dates.dt, cust.dt, by = integer(0)) : 
  A non-empty vector of column names for `by` is required."
#data.table approach
library(data.table)

orders.dt <- data.table(orders)

dates.dt <- data.table(dates)

cust.dt <- unique(orders.dt[, list(first.name, last.name)])

#try to use merge (data.table) in the same manner as base
merge(dates.dt, cust.dt, by = integer(0))
Error in merge.data.table(dates.dt, cust.dt, by = integer(0)) : 
  A non-empty vector of column names for `by` is required.

ベースと同様に、すべての日付のすべての顧客名を結果に反映させたいのですが、data.table 中心の方法でそれを行います。これは可能ですか?

4

3 に答える 3

17

-dataframeの最初と最後から最初にフルネームを作成する場合は、 (相互結合)custを使用できます。CJ99個のアイテムがあり、名が姓と不適切に混在するため、3つのベクトルすべてを使用することはできません。

> 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
于 2012-09-07T17:17:21.900 に答える
7

merge.data.table(x, y)は への呼び出しをラップする便利な関数であるx[y]ため、マージは両方の にある列に基づく必要がありますdata.table。(それが、そのエラー メッセージが伝えようとしているものです)。

回避策の 1 つは、両方の 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]
于 2012-09-07T17:01:37.193 に答える
2

@ JoshO'Brienのソリューションは使用してmergeいますが、以下はそうではない同様の代替手段です(AFAIK)。

ドキュメントを?data.table::merge正しく理解していれば、 (バージョン 1.8.7 の時点で)X[Y]よりもわずかに高速になるはずです。data.table::merge(X,Y)この質問に対処するために FAQ 2.12 を参照していますが、FAQ は少し混乱しています。まず、正しい基準は 2.12 ではなく 1.12 である必要があります。そして、merge のベース バージョンを参照しているのか、data.table を参照しているのか、またはその両方を参照しているのかを示していません。したがって、これは、同等の、またはより高速な、より乱雑に見えるソリューションになる可能性があります。

[ Matthew からの編集] ありがとう : v1.8.7 で改善されました ( ?merge.data.table、FAQ 1.12、および新しい FAQ 2.24 が追加されました)。

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]
于 2013-01-04T20:25:53.573 に答える