如何在data.frame中创建特定列的方法列?

时间:2014-09-17 21:40:47

标签: r dataframe netlogo behaviorspace

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

我有一个data.frame,其中有很多列来自NetLogo生成的BehaviorSpace模型。每列是一个时间序列,表示不同实验条件下的报告值,重复次数由运行次数和时间步数表示。例如(抱歉,这很长,但我试图给你一个数据的味道):

# 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(),我会神秘地获得NAs:

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。 : - )

3 个答案:

答案 0 :(得分:2)

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

# 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

让我们希望这就是您所寻找的。

另一个有趣的补充,如果你不想区分每个重复,而是在治疗水平上

# 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

答案 1 :(得分:1)

使用tidyr和来自magrittr的管道运算符忽略将数据打造成形状的“仅基数”要求:

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

现在,我不确定你到底想要得到的平均值和标准偏差是什么,但是一个简单的选项是来自基础R的aggregate()。简单地通过{你想要的函数传递{ {1}}参数:

FUN

答案 2 :(得分:1)

根据您展示的代码,这种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