首页 > 解决方案 > 如何在数据框中的不同子集上运行 glm 代码并使用提取的值创建新列?

问题描述

我有这段运行 glm 的代码,用于生成受试者对数字刺激列表的响应 [编码为 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))

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

例如,对于每个主题,我想为每个刺激类型“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)

我最初尝试过,但显然这不是要走的路……:

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

我对编码很陌生,所以我希望这一切都有意义!感谢您的任何帮助/见解!

标签: rdplyrglm

解决方案


tidyr::nest我认为这是使用和组合的好地方purrr::map

事实上,正如?nest所说,“嵌套通常对于创建每组模型很有用”。

这是一些代码:

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

在这里,nest除了c(subject, stimtype, block)名为data. 然后您可以map围绕此列应用自定义功能。由于您的函数返回一个双精度值,因此我使用了map_dbl.

编辑

你也可以使用总结:

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

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


推荐阅读