【问题标题】:calculate average over multiple data frames计算多个数据帧的平均值
【发布时间】:2011-01-19 16:19:11
【问题描述】:

我想使用 R 绘制不同数据库系统的性能评估结果。对于每个系统,我加载了相同的数据并在多次迭代中执行相同的查询。

单个系统的数据如下所示:

"iteration", "lines", "loadTime", "query1", "query2", "query3"
1, 100000, 120.4, 0.5, 6.4, 1.2
1, 100000, 110.1, 0.1, 5.2, 2.1
1, 50000, 130.3, 0.2, 4.3, 2.2

2, 100000, 120.4, 0.1, 2.4, 1.2
2, 100000, 300.2, 0.2, 4.5, 1.4
2, 50000, 235.3, 0.4, 4.2, 0.5

3, 100000, 233.5, 0.7, 8.3, 6.7
3, 100000, 300.1, 0.9, 0.5, 4.4
3, 50000, 100.2, 0.4, 9.2, 1.2

我现在需要(用于绘图)是包含这些测量值的平均值的矩阵或数据框。

目前我正在这样做:

# read the file
all_results <- read.csv(file="file.csv", head=TRUE, sep=",")

# split the results by iteration
results <- split(all_results, all_results$iteration)

# convert each result into a data frane
r1 = as.data.frame(results[1])
r2 = as.data.frame(results[2])
r3 = as.data.frame(results[3])

# calculate the average
(r1 + r2 +r3) / 3

我可以将所有这些放入一个函数中,并在 for 循环中计算平均矩阵,但我有一种模糊的感觉,必须有一个更优雅的解决方案。有什么想法吗?

如果我的结果不完整,例如,当一个迭代的行数少于其他迭代时,我该怎么办?

谢谢!

【问题讨论】:

    标签: r


    【解决方案1】:

    如果我理解正确,在给定的数据库系统上,在每个“迭代”(1...N) 中,您正在加载一系列数据集 (1,2,3) 并在它们上运行查询。最后,您似乎想要计算所有迭代的平均时间,每个数据集。如果是这样,您实际上需要在您的all_results 表中添加一个用于标识DataSet 的列DataSet。我们可以按如下方式添加此列:

    all_results <- cbind( data.frame( DataSet = rep(1:3,3) ), all_results )
    > all_results
      DataSet iteration  lines loadTime query1 query2 query3
    1       1         1 100000    120.4    0.5    6.4    1.2
    2       2         1 100000    110.1    0.1    5.2    2.1
    3       3         1  50000    130.3    0.2    4.3    2.2
    4       1         2 100000    120.4    0.1    2.4    1.2
    5       2         2 100000    300.2    0.2    4.5    1.4
    6       3         2  50000    235.3    0.4    4.2    0.5
    7       1         3 100000    233.5    0.7    8.3    6.7
    8       2         3 100000    300.1    0.9    0.5    4.4
    9       3         3  50000    100.2    0.4    9.2    1.2
    

    现在您可以使用 plyr 包中的 ddply 函数轻松提取每个数据集的加载和查询时间的平均值。

    > ddply(all_results, .(DataSet), colwise(mean, .(loadTime, query1, query2)))
      DataSet loadTime    query1 query2
    1       1 158.1000 0.4333333    5.7
    2       2 236.8000 0.4000000    3.4
    3       3 155.2667 0.3333333    5.9
    

    顺便说一句,我强烈建议您查看 Hadley Wickham 的 plyr package,了解一组丰富的数据操作功能

    【讨论】:

    • 确实比 for 循环更优雅...感谢提示。
    • 如果我想在 ddply 的输出帧中包含“lines”列怎么办?我可以通过简单地计算线上的平均值来做到这一点;但这在某种程度上没有意义,因为行号是静态值;
    • 我明白你的意思,但我认为取一堆相同值的“平均值”并没有什么坏处!
    【解决方案2】:

    我不明白您为什么需要将all_results 拆分为iteration。您可以在all_results 上使用aggregate。不需要所有迭代都具有相同数量的观察值。

    Lines <- "iteration, lines, loadTime, query1, query2, query3
    1, 100000, 120.4, 0.5, 6.4, 1.2
    1, 100000, 110.1, 0.1, 5.2, 2.1
    1, 50000, 130.3, 0.2, 4.3, 2.2
    2, 100000, 120.4, 0.1, 2.4, 1.2
    2, 100000, 300.2, 0.2, 4.5, 1.4
    2, 50000, 235.3, 0.4, 4.2, 0.5
    3, 100000, 233.5, 0.7, 8.3, 6.7
    3, 100000, 300.1, 0.9, 0.5, 4.4
    3, 50000, 100.2, 0.4, 9.2, 1.2"
    
    all_results <- read.csv(textConnection(Lines))
    
    aggregate(all_results[,-1], by=all_results[,"iteration",drop=FALSE], mean)
    

    【讨论】:

    • 我认为 OP 需要像我在回答中所说的那样按 DataSet 进行平均,而不是按“迭代”(取具有 100000 行和一个50000 行)。至少这是我对他真正想做的事情的解释。
    • ... 但是使用aggregate 的想法很不错(+1)。我只是想以此作为练习来练习使用plyr
    【解决方案3】:

    你有这样的想法吗?

    do.call("rbind", lapply(results, mean))
    

    【讨论】:

      【解决方案4】:

      试试这个:

      > Reduce("+", results) / length(results)
        DataSet iteration lines loadTime    query1 query2   query3
      1       1         2 1e+05 158.1000 0.4333333    5.7 3.033333
      2       2         2 1e+05 236.8000 0.4000000    3.4 2.633333
      3       3         2 5e+04 155.2667 0.3333333    5.9 1.300000
      

      下面是一个aggregate 解决方案,它也适用于不平衡的情况。假设任何迭代的第 i 行用于数据集 i,并且我们只是在数据集中进行平均。使用aggregate 很简单。唯一棘手的部分是正确地将行分配给数据集,以便它也可以在不平衡的情况下工作。这是由list(data.set = ...) 表达式完成的。

      > it <- all_results$iteration
      > aggregate(all_results, list(data.set = seq_along(it) - match(it, it) + 1), mean)
        data.set iteration lines loadTime    query1 query2   query3
      1        1         2 1e+05 158.1000 0.4333333    5.7 3.033333
      2        2         2 1e+05 236.8000 0.4000000    3.4 2.633333
      3        3         2 5e+04 155.2667 0.3333333    5.9 1.300000
      

      【讨论】:

      • 我想建议同样的事情,但如果每个 data.frame 的大小不同,+ 就不起作用。
      • 数据框大小相同,因为发布者表示他发布的代码确实有效,但只是他想要更“优雅”的东西。
      • @Gabor 我指的是他问题中的最后一句话。
      • 好的。我添加了第二个解决方案。可以定义一个加号函数,但在这种情况下,我认为使用聚合更容易。
      【解决方案5】:

      试试,例如,

      with(all_results, tapply(lines, iteration, mean))
      

      【讨论】:

        猜你喜欢
        • 2022-01-06
        • 2021-06-23
        • 2017-02-06
        • 1970-01-01
        • 2021-06-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多