【问题标题】:How do I create a column of means of specific columns in a data.frame?如何在 data.frame 中创建一列特定列的平均值?
【发布时间】:2014-09-19 13:41:49
【问题描述】:

感谢大家的回复和回答。我可以看到我无意中遗漏了一些可能有助于您更好地理解我的问题的重要细节。我试图保持简单和通用,但这实际上并没有帮助。这是包含更多信息的更新版本。

我有一个data.frame,其中有许多列来自BehaviorSpace 生成的NetLogo 模型。每列是一个时间序列,表示不同实验条件下的报告值,重复次数由运行次数和时间步数表示。例如(对不起,这很长,但我想让您了解一下数据):

# Start by building a fake data.frame that models some of the characteristics of mine:
df <- data.frame(run = c(rep(1,5), rep(2,5), rep(3,5), rep(4,5), rep(5,5), rep(6,5), rep(7,5), rep(8,5)))
df2 <- expand.grid(step = 1:5, fac.a = c(10,1000), fac.b = c(0.5,2.0))
df <- data.frame(run = df$run, rep = c(rep(1,20), rep(2,20)), step = df2$step, fac.a = df2$fac.a, fac.b = df2$fac.b)
log_growth <- function (a, b, x) {(1/(1+a*exp(-b*x))) + rnorm(1,0,0.2)}
set.seed(11)
df$treatment1 <- log_growth(df$fac.a, df$fac.b, df$step)
df$treatment2 <- log_growth(df$fac.a / 2, df$fac.b * 2, df$step)

这会将以下内容放入 df:

> df
   run rep step fac.a fac.b  treatment1  treatment2
1    1   1    1    10   0.5  0.05288201 0.356176584
2    1   1    2    10   0.5  0.12507561 0.600407158
3    1   1    3    10   0.5  0.22081815 0.804671117
4    1   1    4    10   0.5  0.33627099 0.920093934
5    1   1    5    10   0.5  0.46053940 0.971397427
6    2   1    1  1000   0.5 -0.08700866 0.009396323
7    2   1    2  1000   0.5 -0.08594375 0.018552055
8    2   1    3  1000   0.5 -0.08419297 0.042608835
9    2   1    4  1000   0.5 -0.08131981 0.102435481
10   2   1    5  1000   0.5 -0.07661880 0.232875872
11   3   1    1    10   2.0  0.33627099 0.920093934
12   3   1    2    10   2.0  0.75654214 1.002314651
13   3   1    3    10   2.0  0.88715737 1.003958435
14   3   1    4    10   2.0  0.90800192 1.003988593
15   3   1    5    10   2.0  0.91089154 1.003989145
16   4   1    1  1000   2.0 -0.08131981 0.102435481
17   4   1    2  1000   2.0 -0.03688314 0.860350536
18   4   1    3  1000   2.0  0.19880473 1.000926458
19   4   1    4  1000   2.0  0.66014952 1.003932891
20   4   1    5  1000   2.0  0.86791705 1.003988125
21   5   2    1    10   0.5  0.05288201 0.356176584
22   5   2    2    10   0.5  0.12507561 0.600407158
23   5   2    3    10   0.5  0.22081815 0.804671117
24   5   2    4    10   0.5  0.33627099 0.920093934
25   5   2    5    10   0.5  0.46053940 0.971397427
26   6   2    1  1000   0.5 -0.08700866 0.009396323
27   6   2    2  1000   0.5 -0.08594375 0.018552055
28   6   2    3  1000   0.5 -0.08419297 0.042608835
29   6   2    4  1000   0.5 -0.08131981 0.102435481
30   6   2    5  1000   0.5 -0.07661880 0.232875872
31   7   2    1    10   2.0  0.33627099 0.920093934
32   7   2    2    10   2.0  0.75654214 1.002314651
33   7   2    3    10   2.0  0.88715737 1.003958435
34   7   2    4    10   2.0  0.90800192 1.003988593
35   7   2    5    10   2.0  0.91089154 1.003989145
36   8   2    1  1000   2.0 -0.08131981 0.102435481
37   8   2    2  1000   2.0 -0.03688314 0.860350536
38   8   2    3  1000   2.0  0.19880473 1.000926458
39   8   2    4  1000   2.0  0.66014952 1.003932891
40   8   2    5  1000   2.0  0.86791705 1.003988125

所以我之前所做的是使用by 拆分数据框,并希望获得每个步骤(它是一个时间序列)和每个因素组合的平均值和标准偏差。

在查看了您的所有答案并重新考虑了我的问题之后,我认为我正在尝试做的事情在by 的转换过程中会得到更好的处理。我不确定该怎么做...我希望输出看起来像各种摘要:

> df
   run fac.a fac.b  mean.treatment1  mean.treatment2 sd.treatment1 sd.treatment2
1    1    10   0.5        xxxxxxxxx       xxxxxxxxxx    xxxxxxxxxx   xxxxxxxxxxx
1    1    10   2.0        xxxxxxxxx       xxxxxxxxxx    xxxxxxxxxx   xxxxxxxxxxx
1    1  1000   0.5        xxxxxxxxx       xxxxxxxxxx    xxxxxxxxxx   xxxxxxxxxxx
1    1  1000   2.0        xxxxxxxxx       xxxxxxxxxx    xxxxxxxxxx   xxxxxxxxxxx

这是aggregate 的工作吗?感谢您的耐心和帮助。 ——格伦


原问题:

我有一个data.frame 有很多列,每列代表一个特定的重复实验条件。

> df <- data.frame(a.1 = runif(5), b.1 = runif(5), a.2 = runif(5), b.2 = runif(5), mean.a = 0, mean.b = 0, mean.1 = 0, mean.2 = 0)
> df
        a.1       b.1       a.2       b.2 mean.a mean.b   sd.a   sd.b
1 0.9209433 0.3501444 0.3893140 0.3264827      0      0      0      0
2 0.4171254 0.4883140 0.8282384 0.1215129      0      0      0      0
3 0.2291582 0.9419946 0.4089008 0.5665242      0      0      0      0
4 0.3807868 0.1889066 0.8271075 0.4022014      0      0      0      0
5 0.5863078 0.4991847 0.4082745 0.5637367      0      0      0      0

我想找到每个条件和重复的均值和标准差。到目前为止,最直接的方法似乎是:

for (i in c("a.1", "a.2") {df$mean.a <- df$mean.a + df[[i]]}
df$mean.a <- df$mean.a / 2

但是我有 很多 列,而且它们到处都是,所以这看起来真的是劳动密集型和手工操作。更好一点的方法是使用ave():

df$mean.a <- with (df, ave(a.1, a.2))

但如果我想做 sd() 代替,我会神秘地得到 NA:

df$sd.a <- with (df, ave(a.1, a.2, FUN = sd))
> df
        a.1       b.1       a.2       b.2    mean.a mean.b   sd.a   sd.b
1 0.9209433 0.3501444 0.3893140 0.3264827 0.9209433      0     NA      0
2 0.4171254 0.4883140 0.8282384 0.1215129 0.4171254      0     NA      0
3 0.2291582 0.9419946 0.4089008 0.5665242 0.2291582      0     NA      0
4 0.3807868 0.1889066 0.8271075 0.4022014 0.3807868      0     NA      0
5 0.5863078 0.4991847 0.4082745 0.5637367 0.5863078      0     NA      0

如果可能的话,我宁愿不使用外部包,但似乎我缺少一些基本的东西。 This 问题类似,但与 data.tables 相关,而不是 data.frames。

Another 更接近,但使用 ave() 也很繁琐,例如指定第 1-12、15-17 和 26 列作为主题列,而且神秘的是,sd() 会产生这些 NA。似乎应该有一个简单的方法来做到这一点。几乎让我希望Excel。 :-)

【问题讨论】:

  • 你的数据布局很痛苦。您应该使用 `reshape2' 将数据转换为更易于处理的格式。
  • 你明白ave在做什么吗?你每次做meansd 超过一个值。你没有注意到mean.a 列与a.1 完全相同吗?您从 sd 函数获得“神秘”NA 的原因是因为您试图计算一个值的 SD。例如,尝试sd(1)。我建议您使您的示例更具可重复性,并请添加一些所需的输出
  • 如果您在示例中使用set.seed(),那么我们可以reproduce 使用相同的值。您还可以为您的样本数据提供所需的输出吗?当你说你有更多的组合时,这到底是什么意思?点之前的前缀和之后的后缀有更多的组合。而且您正在尝试计算每行均值和标准差?您是否有理由强制使用这种笨拙/堆叠的数据结构?

标签: r dataframe netlogo behaviorspace


【解决方案1】:

让我们首先将您的数据转换为可接受的格式。请注意,根据您的初始要求,此解决方案确实依赖外部库,但它们在今天非常常见且真正节省时间! (plyr 和 reshape2,作者是 R 社区的现象级人物 Hadley Wickham)

# Note how I only used the data columns, initially, there is no mean and sd column in the data frame used at this stage.
df <- data.frame(a.1 = runif(5), b.1 = runif(5), a.2 = runif(5), b.2 = runif(5))

df$repetition = c(1:nrow(df))
library(reshape2)
tmp = melt(df, id.vars = "repetition")
names(tmp)[2] = "condition"

tmp$treatment = substring(tmp$condition,1,1)

这会产生:

> head(tmp)
  repetition condition     value treatment
1          1       a.1 0.6668952         a
2          2       a.1 0.1248151         a
3          3       a.1 0.7082199         a
4          4       a.1 0.9840956         a
5          5       a.1 0.4479190         a
6          1       b.1 0.9381539         b

现在,剩下的就简单了,我们依靠流行的 plyr 包:

library(plyr)
results = ddply(tmp, .(repetition, treatment), summarize, mean = mean(value), sd = sd(value) )

最终结果是

> head(results)
  repetition treatment      mean         sd
1          1         a 0.6777342 0.01532853
2          1         b 0.6734955 0.37428353
3          2         a 0.4533126 0.46456561
4          2         b 0.8441925 0.07260509
5          3         a 0.3967338 0.44050779
6          3         b 0.5886821 0.42635902

希望这就是您要找的。​​p>

一个更有趣的补充,如果你不想区分每次重复,而是在治疗层面上

# addition
results = ddply(tmp, .( treatment), summarize, mean = mean(value), sd = sd(value) )

结果:

> head(results)
  treatment      mean        sd
1         a 0.5817867 0.2954151
2         b 0.6212537 0.3219035

【讨论】:

  • 谢谢,彼得。我试图避免学习更多包的“复杂性”,但您已经展示了plyrreshape2 实际上如何使事情变得简单得多,并且它们非常常用。我只是还没来得及使用它们。谢谢你的好例子。
【解决方案2】:

使用tidyrmagrittr 中的管道运算符忽略“仅基础”要求将数据鞭打成形状:

set.seed(42)
df  <- data.frame(a.1 = runif(5), b.1 = runif(5), a.2 = runif(5), b.2 = runif(5))
df2 <- df %>%
  gather(treatment, value) %>%
  separate(treatment, c("treatment", "repetition"))
head(df2)
#    treatment repetition      value
# 1          a          1 0.13871017
# 2          a          1 0.98889173
# 3          a          1 0.94666823
# 4          a          1 0.08243756
# 5          a          1 0.51421178
# 6          b          1 0.39020347

现在,我不确定您到底想要获得什么平均值和标准差,但一个简单的选择是来自 base R 的 aggregate()。通过 FUN 简单地传递您想要的函数参数:

# calculate mean on treatment (a or b)
aggregate(df2$value, by = list(treatment = df2$treatment), FUN = mean)
#   treatment repetition         x
# 1         a          1 0.5341839
# 2         b          1 0.6633022
# 3         a          2 0.5442395
# 4         b          2 0.4225865

# calculate mean on treatment and repetition
aggregate(df2$value, by = list(treatment = df2$treatment, repetition = df2$repetition, FUN = mean)
#   treatment         x
# 1         a 0.5392117
# 2         b 0.5429444

【讨论】:

    【解决方案3】:

    根据您显示的代码,base R 方法可能会有所帮助:

     set.seed(42)
     df <- data.frame(a.1 = runif(5), b.1 = runif(5), a.2 = runif(5), b.2 = runif(5))
       do.call(cbind,
         lapply(split(seq_along(df),gsub("\\..*", "",colnames(df))), function(x) {
            x1 <- df[,x]
            data.frame(Means=rowMeans(x1, na.rm=TRUE), SD=apply(x1, 1, sd, na.rm=TRUE))}))
      #  a.Means      a.SD   b.Means       b.SD
      #1 0.6862739 0.3231932 0.7295552 0.29763438
      #2 0.8280938 0.1541232 0.8574074 0.17086395
      #3 0.6104059 0.4585819 0.1260770 0.01214755
      #4 0.5429382 0.4065997 0.5659947 0.12869005
      #5 0.5520192 0.1268922 0.6326988 0.10234101
    

    使用您的代码,我得到相同的结果

      vec1 <- vector("numeric", length=5)
      for(i in c("a.1", "a.2")) {vec1 <- vec1+df[[i]]}
      vec1/2
      #[1] 0.6862739 0.8280938 0.6104059 0.5429382 0.5520192
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-02
      • 2018-11-27
      • 1970-01-01
      • 1970-01-01
      • 2015-09-05
      • 1970-01-01
      相关资源
      最近更新 更多