【问题标题】:how do I split a dataframe by row into chunks of n, apply a function and combine?如何将数据帧逐行拆分为 n 块,应用函数并组合?
【发布时间】:2015-10-23 13:52:09
【问题描述】:

我有 130,209 行的 data.frame

> head(dt)

              mLow1 mHigh1 mLow2 mHigh2 meanLow meanHigh        fc     mean
     A_00001  37.00  12.75 99.25  78.50  68.125   45.625 1.4931507  56.8750
     A_00002  31.00  21.50 84.75  53.00  57.875   37.250 1.5536913  47.5625
     A_00003  72.50  26.50 81.75  74.75  77.125   50.625 1.5234568  63.8750

我想将data.frame 拆分为12,在fc 列上应用scale 函数,然后将其合并。这里没有分组变量,否则我会使用ddply。此外,因为 130,209 不能完全被 12 整除,所以生成的 data.frames 将是不平衡的,即 11 data.frames 将有 10,851 行,最后一个将有 10,848 行,但这很好。

那么如何将data.frame 按行拆分为 n 块(在本例中为 12),应用一个函数,然后将它们组合在一起?任何帮助将不胜感激。

更新: 使用两个顶级解决方案,我得到不同的结果: 使用@Ben Bolker 的解决方案,

mLow1 mHigh1 mLow2 mHigh2          UID       gene_id meanLow meanHigh mean         fc
  1.5   3.25     1   1.25 MGLibB_00021 0610010K14Rik    1.25     2.25 1.75 -0.5231249
  1.5   3.25     1   1.25 MGLibA_00034 0610037L13Rik    1.25     2.25 1.75 -0.5231249
  1.5   3.25     1   1.25 MGLibB_00058 1100001G20Rik    1.25     2.25 1.75 -0.5231249
  1.5   3.25     1   1.25 MGLibA_00061 1110001A16Rik    1.25     2.25 1.75 -0.5231249
  1.5   3.25     1   1.25 MGLibA_00104 1110034G24Rik    1.25     2.25 1.75 -0.5231249
  1.5   3.25     1   1.25 MGLibA_00110 1110038F14Rik    1.25     2.25 1.75 -0.5231249

使用@MichaelChirico 的回答:

mLow1 mHigh1 mLow2 mHigh2          UID       gene_id meanLow meanHigh mean        fc  fc_scaled
  1.5   3.25     1   1.25 MGLibB_00021 0610010K14Rik    1.25     2.25 1.75 0.5555556 -0.5089608
  1.5   3.25     1   1.25 MGLibA_00034 0610037L13Rik    1.25     2.25 1.75 0.5555556 -0.5089608
  1.5   3.25     1   1.25 MGLibB_00058 1100001G20Rik    1.25     2.25 1.75 0.5555556 -0.5089608
  1.5   3.25     1   1.25 MGLibA_00061 1110001A16Rik    1.25     2.25 1.75 0.5555556 -0.5089608
  1.5   3.25     1   1.25 MGLibA_00104 1110034G24Rik    1.25     2.25 1.75 0.5555556 -0.5089608
  1.5   3.25     1   1.25 MGLibA_00110 1110038F14Rik    1.25     2.25 1.75 0.5555556 -0.5089608

【问题讨论】:

  • 这个行数不大。为什么要单独操作 scale 并合并结果而不是直接缩放 fc 列??
  • 我想控制平均丰度(平均值)的 fc(倍数变化)。数据在我的实际数据框中按平均值排序。我想为单独的平均丰度块分别计算 zscore(非常低,低......中......高......到非常高)
  • 为什么不使用cut(1:nrow(dt), 12)进行拆分?

标签: r split apply


【解决方案1】:

我不确定dt 的结构是否重要(如果您没有使用它的任何内部值进行拆分)。这有帮助吗?

 spl.dt <- split( dt , cut(1:nrow(dt), 12) )

 lapply( spl.dt, my_fun) 

【讨论】:

  • 谢谢!我尝试了您的解决方案,将 lapply 更改为 ldply 以返回 data.frame 并且它可以工作。
【解决方案2】:

ggplot2 有一个 cut_number() 便利功能,可以为您完成这项工作。如果您不希望加载该包的开销,您可以查看ggplot2:::breaks 以了解必要的逻辑。

从@MichaelChirico 窃取的可重现示例:

set.seed(100)
KK<-130209L; nn<-12L
library("dplyr")
dt <- data.frame(mLow1=rnorm(KK),mHigh1=rnorm(KK),
               mLow2=rnorm(KK),mHigh2=rnorm(KK),
               meanLow=rnorm(KK),meanHigh=rnorm(KK),
               fc=rnorm(KK),mean=rnorm(KK)) %>% arrange(mean)

向不喜欢管道的人道歉:

library("ggplot2")  ## for cut_number()
dt %>% mutate(grp=cut_number(mean,12)) %>%
       group_by(grp) %>%
       mutate(fc=c(scale(fc))) %>%
       ungroup() %>%        
       select(-grp) %>%     ## drop grouping variable
       as.data.frame -> dt2 ## convert back to data frame, assign result

事实证明scale() 周围的c() 是必要的——否则fc 变量最终会带有一些混淆tail() 的属性...

同样的逻辑也应该适用于使用plyr,或者base R split-apply-combine(关键是使用cut_number() 来定义分组变量)。

【讨论】:

  • 很抱歉我不太会使用 dplyr。我得到了一个 [1] "grouped_df" "tbl_df" "tbl" "data.frame" 类的对象。如何在 data.frame 中获取它?我无法查看数据,也无法对其进行as.data.frame
  • 我最后使用了 %>% as.data.frame() 并且它有效。谢谢。
  • 实际上我什至无法访问数据的底部。当我使用 tail() 时,它给了我Error in FUN(X[[i]], ...) : dims [product 10899] do not match the length of object [130209]
【解决方案3】:

使用data.table,您可以:

library(data.table)
setDT(dt)[,scale(fc),by=rep(1:nn,each=ceiling(KK/nn),length.out=KK)]

这里,KK 是 130,209,nn 是 12。可重现的数据:

set.seed(100)
KK<-130209L; nn<-12L
dt<-data.frame(mLow1=rnorm(KK),mHigh1=rnorm(KK),
               mLow2=rnorm(KK),mHigh2=rnorm(KK),
               meanLow=rnorm(KK),meanHigh=rnorm(KK),
               fc=rnorm(KK),mean=rnorm(KK))

因此无需拆分数据并重新组合。

如果您想将其添加到数据框中而不是仅仅提取它,您可以使用:= 运算符通过引用进行分配:

setDT(dt)[,fc_scaled:=scale(fc)...]

【讨论】:

  • 我不能 100% 确定这会以正确的方式划分数据;我想你需要像rep(1:nn,each=ceiling(KK/nn),length.out=KK) 这样的东西?
  • @MichaelChirico 我使用您的解决方案和上面的解决方案得到了不同的结果。
  • 使用这两种解决方案的结果仍然不同。查看更新。
  • 你和@BondedDust 的结果几乎一样,切割略有不同(第4块比其他块小,你的第12块比其他块小)。但这没关系。谢谢!
  • @KomalRathi 好的,我希望它会是这样的。将“剩菜”存储在哪里取决于您的数据结构/您想要做什么,所以我将把决定权留给您。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
相关资源
最近更新 更多