【问题标题】:Calculate a new variable in a series of subsets of one large database在一个大型数据库的一系列子集中计算一个新变量
【发布时间】:2023-03-10 09:36:01
【问题描述】:

我有一个看起来像这样的大型数据库:

      >tms
    expId     id     date sessionNr waveSh ipi isi perc    ampl qual eventNr
1   b80M1 myrthe 20131206         1      2  20   1   80  416.10    1     145
2   b80M1 myrthe 20131206         1      2   4   2   80  366.80    1     146
3   b80M1 myrthe 20131206         1      2   4   3   80  411.60    1     147
    ..... ...... ........         .      .   .   .   ..  ......    .     ... 
    ..... ...... ........         .      .   .   .   ..  ......    .     ...
24  m80M1 myrthe 20131218         1      1  20   2   80   58.10    1     266
25  m80M1 myrthe 20131218         1      1   4   1   80   22.60    0     267
26  m80M1 myrthe 20131218         1      1   4   3   80   21.90    0     268
    ..... ...... ........         .      .   .   .   ..  ......    .     ...
    ..... ...... ........         .      .   .   .   ..  ......    .     ...
201 h80M1 myrthe 20131219         1      3   5   3   80   33.00    0     194
202 h80M1 myrthe 20131219         1      3   6   1   80   52.50    1     195
203 h80M1 myrthe 20131219         1      3   4   4   80  314.20    1     196

在每个 tms$expId 中,我想创建一个名为 tms$norm 的新变量。该变量表示 tms$ampl 与 tms$expId 内 tms$isi==1 的平均值之间的比率,即 tms$ampl/mean(tms[tms$isi==1,]$ampl)。

我可以像这样从长远来看,为每个 tms$expId 手动设置子集:

    b80L1 <- tms[tms$expId==b80L1,]
    attach(b80L1)
    b80L1$norm <- b80L1$ampl/mean(b80L1[b80L1$isi==1,]$ampl)
    detach(b80l1)

    m80M1 <- tms[tms$expId==m80M1,]
    attach(m80M1)
    M80M1$norm <- M80M1$ampl/mean(m80M1[m80M1$isi==1,]$ampl)
    detach(m80M1)

    h80M1 <- h80M1[h80M1$expId==h80M1,]
    attach(h80M1)
    h80M1$norm <- h80M1$ampl/mean(h80M1[h80M1$isi==1,]$ampl)
    detach(h80M1)

然后将所有子集再次组合到一个数据框中,如下所示:

    tmsNorm <- rbind(b80L1,m80M1,h80M1)

那么 tmsNorm 数据库将如下所示:

      >tmsNorm
    expId     id     date sessionNr waveSh ipi isi perc    ampl qual eventNr  norm
1   b80M1 myrthe 20131206         1      2  20   1   80  416.10    1     145  0.6547
2   b80M1 myrthe 20131206         1      2   4   2   80  366.80    1     146  0.5667
3   b80M1 myrthe 20131206         1      2   4   3   80  411.60    1     147  0.6530
    ..... ...... ........         .      .   .   .   ..  ......    .     ...  ...
    ..... ...... ........         .      .   .   .   ..  ......    .     ...  ...
24  m80M1 myrthe 20131218         1      1  20   2   80   58.10    1     266  0.0123
25  m80M1 myrthe 20131218         1      1   4   1   80   22.60    0     267  0.0056
26  m80M1 myrthe 20131218         1      1   4   3   80   21.90    0     268  0.0057
    ..... ...... ........         .      .   .   .   ..  ......    .     ...  ...
    ..... ...... ........         .      .   .   .   ..  ......    .     ...  ...
201 h80M1 myrthe 20131219         1      3   5   3   80   33.00    0     194  0.0045
202 h80M1 myrthe 20131219         1      3   6   1   80   52.50    1     195  0.0053
203 h80M1 myrthe 20131219         1      3   4   4   80  314.20    1     196  0.0145

但是,由于我有大约 100 种类型的 tmse$expId,我真的很想使用循环函数或某种应​​用函数来创建这个 tms$norm 变量。

我尝试使用这个不起作用的代码,但希望能表明我想要实现的目标:

    uniq <- unique(unlist(tms$expId))
   > for(i in 1:length(uniq)){
       attach(tms[tms$expId==uniq[i], ])
       tms$normReal2 <- tms[tms$expId==uniq[i], ]$realAmpl/mean(tms[(tms$expId==uniq[i]) |       (tms$isi==1),]$realAmpl)
       detach(tms[tms$expId==uniq[i], ])
     }

所以我的问题是:如何使用非常紧凑的代码创建这个 tms$norm 变量?

提前非常感谢您!

【问题讨论】:

  • 看看aggregate函数。
  • @user3233153 不清楚您是否对条件 isi==1 为真的数据子集或具有 NA 的完整数据集感兴趣
  • 如果 isi==1,每个 expId,我对 ampl 的平均值感兴趣。所以在上面的数据框选择中,这将是 3 个值。

标签: r variables loops subset


【解决方案1】:

试试 dplyr。

install.packages('dplyr')
require(dplyr)

tms <- group_by(tms, expId)
tms <- mutate(tms, norm = ampl / mean(ampl[isi == 1]))

【讨论】:

  • 哇,答案很快。
  • 但是,由于我拥有 OS X 和 R 版本 3.0.2 的组合,因此无法安装该软件包。有没有可能在没有包装的情况下做到这一点?或者,如何安装 OS X 和 R 版本 3.0.2 的组合包?
  • 对不起,也不起作用。当还安装包“断言”时,它返回:从 hadley 安装 github repo(s) dplyr/master 从github.com/hadley/dplyr/archive/master.zip 下载 dplyr.zip 从...安装包错误:找到包 'Rcpp' 0.10.4,但是'dplyr-master' 需要 >= 0.10.6 * 删除 '/Library/Frameworks/R.framework/Versions/3.0/Resources/library/dplyr' 错误:命令失败 (1)"
  • 我使用的是windows,无法从github安装,谁知道为什么。我安装了 devtools、Rtools 等。但是,它适用于install.packages('dplyr')。奇怪..
  • 终于安装好了,现在运行非常顺利!非常感谢您的帮助!
【解决方案2】:
require(data.table)

set.seed(123)
tms <- data.table(row_id = 1:10e5,
                  expId = letters,
                  isi = c(1,2,3),
                  ampl = rnorm(10e5, 300, 100)
)

编辑

# Keep the original table
tms[isi==1, isi1_mean:=mean(ampl), by=expId]  # The mean of the ampl column when isi==1 by expId
tms[isi==1, norm:=(ampl/isi1_mean), by=expId]


# Keep a subset where isi==1
tms <- data.table(row_id = 1:10e5,
                  expId = letters,
                  isi = c(1,2,3),
                  ampl = rnorm(10e5, 300, 100)
                  )

tms[isi==1, isi1_mean:=mean(ampl), by=expId]  # The mean of the ampl column when isi==1 by expId
tms[, norm:=(ampl/isi1_mean), by=expId][isi==1]

基准测试

我正在尝试使用 data.table 的 dplyr 版本和 data.frame 的版本。我相信这是正确的方法,但如果有不正确的地方,请编辑基准。

require(dplyr)
require(data.table)

set.seed(123)
tms_dt <- data.table(row_id = 1:10e6,
                     expId = letters,
                     isi = c(1,2,3),
                     ampl = rnorm(10e6, 300, 100)
                     )

tms_df <- as.data.frame(tms_dt)

dt_dplyr <- function(data) {
  require(dplyr)
  data <- group_by(data, expId)
  data <- mutate(data, norm = ampl / mean(ampl[isi == 1]))
}

df_dplyr <- function(data) {
  require(dplyr)
  data <- group_by(data, expId)
  data <- mutate(data, norm = ampl / mean(ampl[isi == 1]))
}

dt_datatable <- function(data) {
  data[isi==1, isi1_mean:=mean(ampl), by=expId]
  data[isi==1, norm:=(ampl/isi1_mean), by=expId]
}


require(rbenchmark)
benchmark(dt_dplyr(tms_dt), df_dplyr(tms_df), dt_datatable(tms_dt))
                  test replications elapsed relative user.self sys.self 
2     df_dplyr(tms_df)          100  135.08    1.447    108.81    20.94
3 dt_datatable(tms_dt)          100   93.36    1.000     76.15    16.63
1     dt_dplyr(tms_dt)          100  275.28    2.949    105.34    72.63

【讨论】:

  • 但在这种情况下 mean(ampl))][isi==1] 不是按 expId 计算的,而是在整个数据集上计算的?每个 expId 的平均值 (tms[tms$isi==1,]) 不同...
  • @user3233153 现在正确吗?我正在添加 tms$isi==1 的条件,你想要这个还是更确切地说是原始表和 NA 的 isi 不是 1?
  • 再次出现错误:> 结果 [.data.frame 中的错误(tms, isi == 1, :=(norm, (ampl/mean(ampl))), : 未使用的参数 (by = expId)
  • 它在我的机器上工作,在一个新的 R 会话中。尝试从 R-forge 下载开发版本。 stackoverflow.com/questions/18772277/…
  • 我现在需要一些时间来更好地理解您的答案。不要误会我的意思。你的回答真的很有帮助!
【解决方案3】:

强烈建议您花时间阅读以下内容:http://www.jstatsoft.org/v40/i01/paperSplit Apply Combine

在这种情况下,我想你想要

install.packages(plyr)
require(plyr)
ddply(tms, .(expId), function(x) {data.frame(x, norm=x$ampl/mean(x[x$isi==1,]["ampl"]))})

如果这个答案有错别字,请见谅 - 我自己无法测试。

【讨论】:

  • 感谢您的快速回答。该链接听起来非常有用,将尽快阅读。但是我尝试了代码,并且每个“expId”都会导致警告:“在 mean.default(x[x$isi == 1, ]["ampl"]) 中:参数不是数字或逻辑:返回 NA"
猜你喜欢
  • 2022-01-18
  • 1970-01-01
  • 2019-11-03
  • 2020-06-30
  • 1970-01-01
  • 2020-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多