2016-03-06 82 views
1

我想合并多个向量到数据框。有两个变量,cityid将用于匹配矢量到数据帧。合并,cbind:如何合并更好?

df <- data.frame(array(NA, dim =c(10*50, 2))) 
names(df)<-c("city", "id") 
df[,1]<-rep(1:50, each=10) 
df[,2]<-rep(1:10, 50) 

我创建了一个这样的数据框。在这个数据框中,我想合并50个向量,每个向量对应50个城市。问题是每个城市只有6个obs。每个城市将有4个新手。

给你举个例子,城市1的数据是这样的:

seed(1234) 
cbind(city=1,id=sample(1:10,6),obs=rnorm(6)) 

我有50点城市的数据,我想将它们合并到一列DF。我曾尝试下面的代码:

for(i in 1:50){ 
citydata<-cbind(city=i,id=sample(1:10,6),obs=rnorm(6)) # each city data 
df<-merge(df,citydata, by=c("city", "id"), all=TRUE)} # merge to df 

但是,如果我运行此,循环会显示这样的警告:

In merge.data.frame(df, citydata, by = c("city", "id"), ... : 
    column names ‘obs.x’, ‘obs.y’ are duplicated in the result 

,它会创建50列,而不是一个长列。

如何合并cbind(city=i,id=sample(1:10,6),obs=rnorm(6))df在一个很好的长列中?看起来cbindmerge都不行。


在情况下,有50 citydata(每个都有6行),我可以rbind它们作为一个长数据,并使用data.table方法或expand.gird + merge方式作为菲利普夏侯建议。

我想知道我是否可以通过一个循环合并每个城市数据,而不是rbind他们并合并到df

回答

4

data.table好这个:

library(data.table) 
df <- data.table(df) 
> df 
    city id 
    1: 1 1 
    2: 1 2 
    3: 1 3 
    4: 1 4 
    5: 1 5 
--- 
496: 50 6 
497: 50 7 
498: 50 8 
499: 50 9 
500: 50 10 

我使用CJ,而不是你的for循环,使一些虚拟的数据。 CJ将每个列与每个其他列的每个值交叉连接,因此它会生成一个两列表格,其中每个可能的值对为cityid[,obs:=rnorm(.N)]命令添加第三列,绘制随机值(不会像在CJ中那样回收它们) - .N表示在此上下文中的“此表的#行”。

citydata <- CJ(city=1:50,id=1:6)[,obs:=rnorm(.N)] 
> citydata 
    city id   obs 
    1: 1 1 0.19168335 
    2: 1 2 0.35753229 
    3: 1 3 1.35707865 
    4: 1 4 1.91871907 
    5: 1 5 -0.56961647 
--- 
296: 50 2 0.30592659 
297: 50 3 -0.44989646 
298: 50 4 0.05359738 
299: 50 5 -0.57494269 
300: 50 6 0.09565473 

setkey(df,city,id) 
setkey(citydata,city,id) 

由于这两个表具有相同的键列下面查找的df行由键列citydata,然后在df通过查找citydata值定义obs。因此所得到的对象是原始df但具有限定obs无论它在citydata定义:

citydata <- expand.grid(city=1:50,id=1:6) 
citydata$obs <- rnorm(nrow(citydata)) 

res <- merge(df, citydata, by = c("city","id"), all.x = TRUE) 

其给出:

df[citydata,obs:=i.obs] 
> df 
    city id   obs 
    1: 1 1 0.19168335 
    2: 1 2 0.35753229 
    3: 1 3 1.35707865 
    4: 1 4 1.91871907 
    5: 1 5 -0.56961647 
--- 
496: 50 6 0.09565473 
497: 50 7   NA 
498: 50 8   NA 
499: 50 9   NA 
500: 50 10   NA 
+1

或evrything一气呵成:'setDT(DF)[CJ(城市= 1:50, id = 1:6)[,obs:= rnorm(.N)],obs:= i.obs,on = c(“city”,“id”)] []' – Jaap

+0

不错。 (但是我也猜测OP有预先存在的真实城市数据,所以创建连接表更多的是展示合并的工作原理,而不是实际解决方案工作流的一部分。) – Philip

+0

Thanx。看看这个问题,我认为这很可能是'citydata'是已经存在的数据,'df'必须用'CJ'来构建才能得到想要的结果。 – Jaap

2

在基础R可以用的expand.gridmerge组合要这样做:

> head(res,12) 
    city id  obs 
1: 1 1 -0.3121133 
2: 1 2 -1.3554576 
3: 1 3 -0.9056468 
4: 1 4 -0.6511869 
5: 1 5 -1.0447499 
6: 1 6 1.5939187 
7: 1 7   NA 
8: 1 8   NA 
9: 1 9   NA 
10: 1 10   NA 
11: 2 1 0.5423479 
12: 2 2 -2.3663335 

dplyr类似的方法tidyr:其给出

library(dplyr) 
library(tidyr) 

res <- crossing(city=1:50,id=1:6) %>% 
    mutate(obs = rnorm(n())) %>% 
    right_join(., df, by = c("city","id")) 

> res 
Source: local data frame [500 x 3] 

    city id  obs 
    (int) (int)  (dbl) 
1  1  1 -0.5335660 
2  1  2 1.0582001 
3  1  3 -1.3888310 
4  1  4 1.8519262 
5  1  5 -0.9971686 
6  1  6 1.3508046 
7  1  7   NA 
8  1  8   NA 
9  1  9   NA 
10  1 10   NA 
.. ... ...  ...