如何 运行 对数据框中的不同子集进行 glm 编码并使用提取的值创建新列?

How to run glm code over different subsets within dataframe & create new column with the extracted values?

我有这段代码 运行 是一个 glm,用于生成受试者对 "midpoint" 的反应 [编码为 trochiac/iambic、0 或 1]数字刺激列表,将中点保存为一个值并在控制台中打印该值。

glm.1 <- glm(coderesponse~stimulus, family = binomial(link="logit"), data=data)
midpoint <- -glm.1$coefficients[1]/glm.1$coefficients[2]
cat(sprintf("file : %s\nmidpoint : %.2f",datafile,midpoint))

目前,此代码 运行 遍及整个数据帧。我想知道如何修改这段代码,以便我可以 运行 它在我的主数据框中的各个子组上,并为每个子组创建一个包含这些值的新列?

例如对于每个主题,我想为每个 stimtype "bd"、"nm" 和 "nm" 中的每个块 (1-8) 生成中点值。该中点值将是每个 stimtype 中每个块的所有行的新创建列中的新值。

我们最终还希望将要减少的每个块的值聚合到包含中点值的一行(而不是让所有行都具有相同的值)。

我的主数据框的小型虚拟版本(仅包含一个主题和最多 6 个刺激):

subject <- c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2)
stimulus <- c(1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1)
block <- c(3, 3, 3, 7, 7, 7, 4, 4, 4, 8, 8, 8, 1, 1, 1, 5, 5, 5, 2, 2, 2, 6, 6, 6, 3, 3, 3, 7, 7, 7, 4, 4, 4, 8, 8, 8, 2, 2, 2, 6, 6, 6)
blockprocedure <- c(1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1)
stimtype <- c('bd', 'nd', 'nm', 'bd', 'nd', 'nm', 'bd', 'nd', 'nm', 'bd', 'nd', 'nm', 'bd', 'nd', 'nm', 'bd', 'nd', 'nm', 'bd', 'nd', 'nm', 'bd', 'nd', 'nm', 'bd', 'nd', 'nm', 'bd', 'nd', 'nm', 'bd', 'nd', 'nm', 'bd', 'nd', 'nm', 'bd', 'nd', 'nm', 'bd', 'nd', 'nm')
blocktype <- c('mouth', 'mouth', 'mouth', 'nose', 'nose', 'nose', 'mouth', 'mouth', 'mouth', 'nose', 'nose', 'nose', 'mouth', 'mouth', 'mouth', 'nose', 'nose', 'nose', 'mouth', 'mouth', 'mouth', 'nose', 'nose', 'nose', 'mouth', 'mouth', 'mouth', 'nose', 'nose', 'nose', 'mouth', 'mouth', 'mouth', 'nose', 'nose', 'nose', 'mouth', 'mouth', 'mouth', 'nose', 'nose', 'nose')
coderesponse <- c(1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1)

dummy = data.frame(subject, stimulus, block, stimtype, blockprocedure, blocktype, coderesponse)

我最初尝试过,但显然这不是要走的路...:[=​​14=]

dummy <- data %>% 
  group_by(subject, stimtype, block)
dummy$test <- NA

glm.1 <- glm(coderesponse~stimulus, family = binomial(link="logit"), data=dummy)
midpoint <- -glm.1$coefficients[1]/glm.1$coefficients[2]
dummy$test <- midpoint

我对编码还很陌生,所以我希望这一切都有意义! 感谢您的任何 help/insight!

我认为这是使用 tidyr::nestpurrr::map 组合的好地方。

的确,正如?nest所说,"Nesting is often useful for creating per group models"。

这是一些代码:

library(dplyr)
library(tidyr)
library(purrr)

get_midpoint = function(data){
  glm.1 = glm(coderesponse~stimulus, family = binomial(link="logit"), data=data)
  rtn = -glm.1$coefficients[1]/glm.1$coefficients[2]
  rtn
}

dummy %>% 
  nest(data=-c(subject, stimtype, block)) %>%
  mutate(midpoint=map_dbl(data, get_midpoint))
# A tibble: 30 x 5
   subject block stimtype data             midpoint
     <dbl> <dbl> <fct>    <list>              <dbl>
 1       1     3 bd       <tibble [2 x 4]> -1.69e11
 2       1     3 nd       <tibble [2 x 4]> -1.69e11
 3       1     3 nm       <tibble [2 x 4]> -1.69e11
 4       1     7 bd       <tibble [2 x 4]>  3.00e 0
 5       1     7 nd       <tibble [2 x 4]> -1.69e11
 6       1     7 nm       <tibble [2 x 4]> -1.69e11
 7       1     4 bd       <tibble [2 x 4]>  4.00e 0
 8       1     4 nd       <tibble [2 x 4]>  4.00e 0
 9       1     4 nm       <tibble [2 x 4]> -1.96e11
10       1     8 bd       <tibble [2 x 4]>  4.00e 0

在这里,您可以在名为 data 的列中 nestc(subject, stimtype, block) 之外的所有列。然后,您可以 map 围绕此列应用自定义函数。作为你的函数 returns a double,我使用了 map_dbl.

编辑

你也可以使用总结:

dummy %>% 
  group_by(subject, stimtype, block) %>% 
  summarise(midpoint = get_midpoint(tibble(coderesponse, stimulus)))

这会输出相同的结果(尽管顺序不同)。