将数据帧拆分为数据帧列表,但如何重新合并?

时间:2012-11-07 19:25:24

标签: r split

我有一个大的数据框,其中包含两个用于课程和用户的ID列,我需要将每个课程拆分为一个数据框,以进行进一步的分析/子集化。在从每个单独的课程数据框中删除了很多行之后,我需要将它们重新组合在一起。

我把它分开使用,你猜对了,split,这就像我需要它一样。然而,未分裂比我想象的更难。 R文档说“unsplit颠倒了split的效果”,但到目前为止我在网上的阅读表明,当拆分列表的元素本身是数据帧时,情况并非如此。

如何重新加入我修改过的dfs?

4 个答案:

答案 0 :(得分:13)

这是do.call的地方。简单地调用df <- rbind(split.df)会导致一个奇怪且无用的列表对象,但do.call("rbind", split.df)应该会为您提供所需的结果。

答案 1 :(得分:5)

unsplit()将在您描述的一般情况下工作/确实起作用,但不会从如此拆分的数据框中删除行的特定情况。

考虑

> spl <- split(mtcars, mtcars$cyl)
> str(spl, max = 1)
List of 3
 $ 4:'data.frame':  11 obs. of  11 variables:
 $ 6:'data.frame':  7 obs. of  11 variables:
 $ 8:'data.frame':  14 obs. of  11 variables:
> str(unsplit(spl, f = mtcars$cyl))
'data.frame':   32 obs. of  11 variables:
 $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
 $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
 $ disp: num  160 160 108 258 360 ...
 $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
 $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
 $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
 $ qsec: num  16.5 17 18.6 19.4 17 ...
 $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
 $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
 $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
 $ carb: num  4 4 1 1 2 1 4 2 2 4 ...

我们可以看到,unsplit()可以撤消拆分。然而,在进一步处理分割数据帧并改变以去除行的情况下,分割列表中的数据帧中的总行数与用于分割原始数据帧的变量之间将存在不匹配。

如果您知道或可以计算使变量用于拆分原始数据框所需的更改,则可以部署unsplit()。虽然这很可能不会是微不足道的。

一般的解决方案是,正如@Andrew Sannier提到的do.call(rbind, ...)成语:

> spl <- split(mtcars, mtcars$cyl)
> str(do.call(rbind, spl))
'data.frame':   32 obs. of  11 variables:
 $ mpg : num  22.8 24.4 22.8 32.4 30.4 33.9 21.5 27.3 26 30.4 ...
 $ cyl : num  4 4 4 4 4 4 4 4 4 4 ...
 $ disp: num  108 146.7 140.8 78.7 75.7 ...
 $ hp  : num  93 62 95 66 52 65 97 66 91 113 ...
 $ drat: num  3.85 3.69 3.92 4.08 4.93 4.22 3.7 4.08 4.43 3.77 ...
 $ wt  : num  2.32 3.19 3.15 2.2 1.61 ...
 $ qsec: num  18.6 20 22.9 19.5 18.5 ...
 $ vs  : num  1 1 1 1 1 1 1 1 0 1 ...
 $ am  : num  1 0 0 1 1 1 0 1 1 1 ...
 $ gear: num  4 4 4 4 4 4 3 4 5 5 ...
 $ carb: num  1 2 2 1 2 1 1 1 2 2 ...

答案 2 :(得分:1)

Andrew Sannier的答案有效,但副作用是rownames被改变了。 rbind将列表名称添加到其中,例如“Datsun 710”成为“4.Datsun 710”。可以在两者之间使用unname来避免此问题。

完整示例:

mtcars_reorder = mtcars[order(mtcars$cyl), ] #reorder based on cyl first
l1 = split(mtcars_reorder, mtcars_reorder$cyl) #split by cyl
l1 = unname(l1) #remove list names
l2 = do.call(what = "rbind", l1) #unsplit
all(l2 == mtcars_reorder) #check if matches
#> TRUE

答案 3 :(得分:1)

在基地R之外,还要考虑:

  • 'void (*)(int)',结果的副作用是data.table::rbindlist()
  • data.table尽管名称有点令人困惑,但仍会在列表中绑定行