【问题标题】:Is there a way to get dplyr's bind_cols to expand number of rows like in cbind?有没有办法让 dplyr 的 bind_cols 像 cbind 一样扩展行数?
【发布时间】:2016-11-10 21:59:12
【问题描述】:

来自?dplyr::bind_cols

这是 do.call(rbind, dfs) 或 do.call(cbind, dfs) 的通用模式的有效实现,用于将多个数据帧绑定到一个中

但是,使用示例数据:

tmp_df1 <- data.frame(a = 1)
tmp_df2 <- data.frame(b = c(-2, 2))
tmp_df3 <- data.frame(c = runif(10))

命令do.call(cbind, list(tmp_df1, tmp_df2, tmp_df3)) 产生:

   a  b         c
1  1 -2 0.8473307
2  1  2 0.8031552
3  1 -2 0.3057430
4  1  2 0.6344999
5  1 -2 0.7870753
6  1  2 0.9453199
7  1 -2 0.6642231
8  1  2 0.9708049
9  1 -2 0.7189576
10 1  2 0.9217087

也就是说,tmp_df1tmp_df2 的行被回收以匹配 tmp_df3 中的行数。

dplyr:

> bind_cols(tmp_df1, tmp_df2, tmp_df3)
Error in eval(substitute(expr), envir, enclos) : 
  incompatible number of rows (2, expecting 1)

我之所以想做这样的事情是因为我处于类似于以下的情况:

df_normal_param <- df(mu = rnorm(10), sigma = runif(10))

df_normal_sample_list <- lapply(1:10, function(i) 
                         with(df_normal_param, 
                              data.frame(sam = rnorm(100, mu[i], sigma[i]))

我希望将用于创建df_normal_sample_list 的每个条目的参数附加到输出中,例如

df_normal_sample_list <- lapply(1:10, function(i) 
                         cbind(df_normal_param[i,], df_normal_sample_list[[i]]))

【问题讨论】:

  • 其中一个示例明确指出它不会做你想做的事:# Rows do need to match when column-binding bind_cols(data.frame(x = 1), data.frame(y = 1:2)) 所以我认为这是一个有意的设计决策,很难在 dplyr 中规避。
  • tidyr::fill() 是我能想到的最接近填充缺失值的方法。通常,根据排序位置将数据库表粘合在一起会产生糟糕的结果;感觉这就是安全胶带的原因。
  • 就我而言,它既安全又合意。我有一个函数f(x,y,z),它产生一个多行的数据框。我有另一个包含 x、y、z 列的数据框,因此该数据框的每一行都为函数 f 提供参数。我想cbind 用于创建f 输出的参数与f 的输出稍后做一些分析。

标签: r dplyr


【解决方案1】:

您在评论中争辩说这种行为是安全的,我强烈反对。对于这种非常特殊的情况,这似乎是安全的,但它可能会在未来的某个地方给您带来问题。这就是为什么我相信你所说的问题的答案(“有没有办法让 dplyr 的 bind_cols 像在 cbind 中一样扩展行数?”)很简单:不,他们可能是故意这样构建的。

相反,我建议您在方法中更加明确,只需在构建您正在创建的数据时添加您想要的列。例如,您可以在通话中直接包含该步骤(此处使用apply 来说明将要做什么)

df <- data.frame(mu = rnorm(3), sigma = runif(3))

df_normal_sample_list <- apply(df, 1, function(x){
  data.frame(
    mu = x["mu"]
    , sigma = x["sigma"]
    , sam = rnorm(3, x["mu"], x["sigma"])
  )
})

返回

[[1]]
          mu     sigma       sam
1 -0.6982395 0.1690402 -0.592286
2 -0.6982395 0.1690402 -0.516948
3 -0.6982395 0.1690402 -0.804366

[[2]]
         mu     sigma       sam
1 -1.698747 0.2597186 -1.830950
2 -1.698747 0.2597186 -2.087393
3 -1.698747 0.2597186 -1.961376

[[3]]
         mu     sigma       sam
1 0.9913492 0.3069877 0.9629801
2 0.9913492 0.3069877 1.2279697
3 0.9913492 0.3069877 1.1222780

然后,除了绑定列,再绑定行,您可以只绑定最后的行(也来自dplyr

bind_rows(df_normal_sample_list)

【讨论】:

  • 对于交替值,只需在分配值之前过滤所有偶数行%2 == 0
  • 你能举个例子,你认为这会给我带来麻烦吗?
  • 最可能的情况是您的df_normal_param 在您进行合并之前发生更改。如果您更改某些内容而忘记重新创建df_normal_sample_list,或者如果创建新的df_normal_sample_list 时出错,而您没有发现它,因此意外合并到旧版本,则可能会发生这种情况。在创建输出时也很容易错过改变某些东西的变化(例如,每组的行数)。我也遇到了偶尔返回 NULL 或 NA 的函数的实质性问题——根据细节,cbind 对这些函数的处理方式非常不同
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-23
相关资源
最近更新 更多