【问题标题】:How to ddply() without sorting?如何在不排序的情况下进行 ddply()?
【发布时间】:2011-11-06 07:37:35
【问题描述】:

我使用以下代码汇总我的数据,按 Compound、Replicate 和 Mass 分组。

summaryDataFrame <- ddply(reviewDataFrame, .(Compound, Replicate, Mass), 
  .fun = calculate_T60_Over_T0_Ratio)

一个不幸的副作用是生成的数据帧按这些字段排序。我想这样做并保持 Compound、Replicate 和 Mass 的顺序与原始数据框中的顺序相同。有任何想法吗?我尝试将顺序整数的“排序”列添加到原始数据中,但是我当然不能将其包含在 .variables 中,因为我不想对其进行“分组”,因此它不会在summaryDataFrame。

感谢您的帮助。

【问题讨论】:

  • 这与write.table无关;标题应该改变。

标签: r sorting plyr


【解决方案1】:

这在不久前出现在 plyr 邮件列表中(由 @kohske 提出),这是 Peter Meil​​strup 为有限情况提供的解决方案:

#Peter's version used a function gensym to
# create the col name, but I couldn't track down
# what package it was in.
keeping.order <- function(data, fn, ...) { 
  col <- ".sortColumn"
  data[,col] <- 1:nrow(data) 
  out <- fn(data, ...) 
  if (!col %in% colnames(out)) stop("Ordering column not preserved by function") 
  out <- out[order(out[,col]),] 
  out[,col] <- NULL 
  out 
} 

#Some sample data 
d <- structure(list(g = c(2L, 2L, 1L, 1L, 2L, 2L), v = c(-1.90127112738315, 
-1.20862680183042, -1.13913266070505, 0.14899803094742, -0.69427656843677, 
0.872558638137971)), .Names = c("g", "v"), row.names = c(NA, 
-6L), class = "data.frame") 

#This one resorts
ddply(d, .(g), mutate, v=scale(v)) #does not preserve order of d 

#This one does not
keeping.order(d, ddply, .(g), mutate, v=scale(v)) #preserves order of d 

请阅读 thread,了解 Hadley 的说明,了解为什么此功能可能不够通用,无法转入 ddply,特别是因为它可能适用于您的情况,因为您可能每件返回的行数较少。

已编辑以包含更一般情况的策略

如果 ddply 输出的内容按您不喜欢的顺序排序,您基本上有两个选择:使用有序因子预先指定拆分变量的所需排序,或事后手动对输出进行排序。

例如,考虑以下数据:

d <- data.frame(x1 = rep(letters[1:3],each = 5), 
                x2 = rep(letters[4:6],5),
                x3 = 1:15,stringsAsFactors = FALSE)

暂时使用字符串。 ddply 将对输出进行排序,在这种情况下将需要默认的词法排序:

> ddply(d,.(x1,x2),summarise, val = sum(x3))
  x1 x2 val
1  a  d   5
2  a  e   7
3  a  f   3
4  b  d  17
5  b  e   8
6  b  f  15
7  c  d  13
8  c  e  25
9  c  f  27


> ddply(d[sample(1:15,15),],.(x1,x2),summarise, val = sum(x3))
  x1 x2 val
1  a  d   5
2  a  e   7
3  a  f   3
4  b  d  17
5  b  e   8
6  b  f  15
7  c  d  13
8  c  e  25
9  c  f  27

如果生成的数据框没有以“正确”的顺序结束,可能是因为您确实希望其中一些变量成为有序因子。假设我们真的想要 x1x2 像这样排序:

d$x1 <- factor(d$x1, levels = c('b','a','c'),ordered = TRUE)
d$x2 <- factor(d$x2, levels = c('d','f','e'), ordered = TRUE)

现在当我们使用ddply 时,结果排序将如我们所愿:

> ddply(d,.(x1,x2),summarise, val = sum(x3))
  x1 x2 val
1  b  d  17
2  b  f  15
3  b  e   8
4  a  d   5
5  a  f   3
6  a  e   7
7  c  d  13
8  c  f  27
9  c  e  25

这里的故事的寓意是,如果 ddply 以您不希望的顺序输出某些东西,这是一个好兆头,表明您应该对要拆分的变量使用有序因子。

【讨论】:

  • 谢谢。这似乎“几乎”对我有用。如何在函数返回的数据中保留.sortColumncalculate_T60_Over_T0_Ratio &lt;- function(df) {## checks to make sure the right time points are being used for the ratiot60Value = df[which(df[,"Time"] == "t=60"),"Result"]t0Value = df[which(df[,"Time"] == "t=0"),"Result"]if (t0Value == 0){print("Error -- Divide by zero!")return ("NA")} else {} else {return (t60Value / t0Value) }}
  • @James 如果您想在结果中保留.sortColumn,您可能只需从keeping.order 中省略out[,col] &lt;- NULL 行。
  • 对不起,我不清楚。我收到来自keeping.order 的错误,因为我的函数没有返回.sortColumn(见上文)。
  • @James - 抱歉,我误会了。请记住,我在回答中指出,如果您的函数返回的行数较少(看起来您就是这样),则此策略将不起作用。类似的事情可能是可能的,但它必须专门针对您的数据和功能量身定制,因此除非您编辑您的问题以包含一些示例数据,否则我(或其他任何人)将无能为力。但我现在可以告诉你,它只需要调用ddply,然后再重新排序你的数据。
【解决方案2】:

我最终在原始数据框中添加了一个“索引”列。它由两列pastedsep="_" 组成。然后我制作了另一个数据框,仅由“索引”列的unique 成员和一个计数器1:length(df) 组成。我对返回排序数据框的数据执行了ddply()。然后为了让事情恢复到原来的顺序,我做了merge() 结果数据框和索引数据框(确保列被命名为相同的东西使这更容易)。最后,我做了order 并删除了无关的列。

不是一个优雅的解决方案,而是一个有效的解决方案。

感谢您的帮助。这让我想到了正确的方向。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-16
    • 2023-03-28
    • 2020-01-25
    • 1970-01-01
    • 2022-12-31
    • 2017-05-07
    • 1970-01-01
    相关资源
    最近更新 更多