【问题标题】:R dplyr chaining group by into functionR dplyr 将 group by 链接到函数中
【发布时间】:2016-11-01 23:49:15
【问题描述】:

我有一个看起来像这样的数据框:

  time id trialNum trialType        accX     gravX
1    1  6        7       low -0.38876217 10.185266
2    2  1        6       low  0.68254705 10.741545
3    3  3       15      high -0.21906854  9.466929
4    4  2       15      none -0.03370001  9.490829
5    5  4        1      high  0.16511542 10.986796
6    6  9        2      none -0.10441621  9.915561

你可以使用这个来生成类似的东西:

testDF <- data.frame(time = 1:50,
                     id = sample(1:10, size=50, replace=T),
                     trialNum = sample(1:15, size = 50, replace=T),
                     trialType = sample(c("none", "low", "high"),
                                        size = 50, replace=T),
                     accX = sin(seq(1,50,1)),
                     gravX = 0.1)

还有一个函数来计算滤波信号中峰值之间的平均时间(返回平均时间和时间差的方差):

library(dplyr)
library(signal)
library(quantmod)

calcStepTime <- function(df){
  bf <- butter(1, c(0.03,0.05), type="pass")
  filtered <- filtfilt(bf, df$accX - df$gravX)

  peaks            <- findPeaks(filtered)
  peakValue        <- filtered[peaks]
  peakTime         <- df$time[peaks]

  timeDifferences  <- diff(peakTime)
  meanStepTime     <- mean(timeDifferences)
  varianceStepTime <- var(timeDifferences)

  return(c(meanStepTime, varianceStepTime))
}

我正在尝试使用groupby 将此函数应用于idtrialNumtrialType 的每个组合:

tempTrial <-
    group_by(testDF, id, trialNum, trialType) %>%
    summarise(meanTime = calcStepTime(.)[1],
              varianceTime= calcStepTime(.)[2])

问题在于,在输出数据帧 (tempTrial) 中,meanTimevarianceTime 的每一行都是相同的

在这个玩具数据集中,有时列都显示NA(这在我的实际数据集中不会发生)

我是否做错了什么导致两列的每一行都相同?它应该采用idtrialNumtrialType 的每个组合,并分别计算每个组合的峰值时间。但是,它似乎只为每个组合存储一个值?

【问题讨论】:

  • 我收到一个错误。 Error: could not find function "butter" 请提供库名称。
  • 这里,findPeaks(filtered) 返回numeric(0)
  • 您正在通过几个变量对一个相对较小的数据框进行分组,这意味着您的“分组”数据框可能与您的原始数据框大小相同(或接近)。如果是这样,每组都是一行长,不可能在一行中找到一个峰值。
  • 我已经调整了上面的 testDF 代码,因此它不再通过生成正弦波来生成 NA。这应该可以解决 numeric(0) 问题。我知道测试数据很小,但我的实际数据大约是 100,000 行,所以其他地方肯定有问题,因为无论样本大小如何,我在每一行中都得到相同的数字
  • 小团体的问题在总结中仅次于.的使用问题。虽然修复小组或防御性编码以使其不再生成NANaN 是值得的,但除非您意识到summarise 和@987654344 的组合,否则问题不会得到解决@ 是问题所在。

标签: r filtering dplyr signal-processing


【解决方案1】:

正如您和 Latrunculia 所指出的,calcStepTime 很可能在 50 个观测数据集上返回 NaN/NA。当在一组观察中没有发现峰值或单个峰值时,就会发生这种情况。您可能希望在分析代码中对此进行防御。我用它来测试:

testDF <- data.frame(time = 1:200, 
                 id = sample(1:2, size=200, replace=T), 
                 trialNum = sample(1:1, size = 200, replace=T), 
                 trialType = sample(c("low"), size = 200, replace=T), 
                 accX = sin(seq(1,200,1)), 
                 gravX = 0.1)

如果您更改data_frame (tibble) 函数的返回类型,如下所示:

calcStepTime <- function(df){
  bf <- butter(1, c(0.03,0.05), type="pass")
  filtered <- filtfilt(bf, df$accX - df$gravX)

  peaks <- findPeaks(filtered)
  peakValue <- filtered[peaks]
  peakTime <- df$time[peaks]

  timeDifferences <- diff(peakTime)

  meanStepTime <- mean(timeDifferences)

  varianceStepTime <- var(timeDifferences)

  return (data_frame("meanStepTime" = meanStepTime, 
                     "varianceStepTime" = varianceStepTime))
}

然后您可以利用purrr::by_slice() 获得相当优雅的解决方案:

library(purrr)
testDF %>%
group_by(id, trialNum, trialType) %>%
by_slice(calcStepTime, .collate="cols")

我从我的测试样本中得到了这个:

# A tibble: 2 x 5
     id trialNum trialType meanStepTime1 varianceStepTime1
    <int>    <int>    <fctr>         <dbl>             <dbl>
1     1        1       low         42.75          802.2500
2     2        1       low         39.75          616.9167

请注意,.collate="cols" 是告诉by_slice() 为输出中的结果创建命名列的重要参数。我自己对为什么将“1”附加到我们在您的函数返回的 data_frame 中设置的名称有点好奇。

【讨论】:

    【解决方案2】:

    . 引用分组数据框group_by(testDF, id, trialNum, trialType) 的意义上,链正常工作。由于您定义的函数无法使用. 中的组信息,因此结果就是您所看到的(即应用于整个数据框的函数)。

    所以这里的问题是summarise 的使用不正确。 Latrunculia 的回答向您展示了以您期望的方式使用 summarise 的正确方法是将函数应用于数据框中的列组合,在这种情况下,函数在每个变量中按组应用。

    dplyr 有一个do 函数,适用于您希望将函数应用于group_by 隐含的数据框子集的应用程序。只需将您的summarise 替换为do

    tempTrial <- group_by(testDF, id, trialNum, trialType) %>% do(meanTime = calcStepTime(.)[1], varianceTime= calcStepTime(.)[2])
    

    do 的文档不是很清楚,但this post 很好地描述了该应用程序。

    【讨论】:

      【解决方案3】:

      您现在得到的是calcStepTime 应用于每个组的整个(未分组)数据框的结果。

      尝试重写函数,使其依赖于变量,而不是数据框。

      alcStepTime <- function(var1, var2, var3){
        bf <- butter(1, c(0.03,0.05), type="pass")
        filtered <- filtfilt(bf, var1 - var2)
      
        peaks <- findPeaks(filtered)
        peakValue <- filtered[peaks]
        peakTime <- var3[peaks]
      
        timeDifferences <- diff(peakTime)
      
        meanStepTime <- mean(timeDifferences)
      
        varianceStepTime <- var(timeDifferences)
      
        return(c(meanStepTime, varianceStepTime))
      }
      
      
      
      testDF %>% group_by(testDF, id, trialNum, trialType) %>%
       summarise(meanTime = calcStepTime( accX, gravX, time)[1], 
              varianceTime= calcStepTime(accX, gravX, time)[2])
      

      如果您只是将 testDF 数据框输入其中,它会给出正确的结果。它为分组的 DF 中断,但我找不到这是因为没有为子集定义函数,还是函数有问题。

      让我知道它是否适用于完整数据

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-04-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-14
        • 2018-04-17
        相关资源
        最近更新 更多