【问题标题】:Using a vector to index a data.frame in R使用向量来索引 R 中的 data.frame
【发布时间】:2021-08-17 15:54:53
【问题描述】:

我有一个 data.frame,其中包含一个 ID 号和来自调查的缩放响应:

df(responses)

ID    X1    X2    X3    X4
A1    1     1     2     1
B2    0     1     3     0
C3    3     3     2     0

我还有一个 data.frame 用作键:

df(key)

X    Y    Z
2    1    1
3    2    2
4    3    4

我正在尝试编写一个脚本来计算每个参与者的XYZ 分数,其中X 分数是@987654327 下列出的问题的答案总和@ 在键中。

例如参与者A1X 分数将等于A1(1+2+1 = 4)X2X3X4 的总和。

想要的输出是:

df(output)

ID    X    Y    Z
A1    4    4    3
B2    4    4    1
C3    5    8    6

但是,我目前正在努力使用 key 中的值索引 data.frame responses。我现在的状态是:

#store scale names
scales <- c(colnames(key))
#loop over every participant
for (i in responses$ID){
    #create temporary data.frame with only participant "i"s responses
    data <- subset(responses, ID == i)
    #loop over each scale and store the relevant response numbers
    for (s in scales){
        relevantResponses <- scales[c(s)]
        #create a temporary storage for the total of each scale
        runningScore <- 0
        #index each response and add it to the total
        for (r in relevantResponses){
             runningScore <- runningScore + data[1,r]
  

但是我得到了错误:

Error in `[.data.frame`(data, 1, r) : 
  undefined columns selected

有没有比嵌套循环更好的索引方法?

【问题讨论】:

    标签: r dplyr purrr


    【解决方案1】:

    我们可以使用rowSums 循环lapplykey 数据列,根据索引提取“响应”数字列,得到rowSumslist 转换为data.frame 和@ 987654327@ 第一列是'responses'

    cbind(responses[1], data.frame(lapply(key, 
         function(x) rowSums(responses[-1][, na.omit(x)], na.rm = TRUE))))
    

    -输出

    #  ID X Y Z
    #1 A1 4 4 3
    #2 B2 4 4 1
    #3 C3 5 8 6
    

    或者tidyverse

    imap(key, ~ responses %>%
         transmute(ID, !!.y :=  rowSums(select(cur_data()[-1], na.omit(.x)),
              na.rm = TRUE))) %>% 
         reduce(inner_join)
    

    -输出

    #  ID X Y Z
    #1 A1 4 4 3
    #2 B2 4 4 1
    #3 C3 5 8 6
    

    或者另一个选项是mutateacross

    key %>%
       mutate(across(everything(), 
           ~ rowSums(responses[-1][na.omit(.)], na.rm = TRUE)), 
              ID = responses$ID, .before = 1)
    #  ID X Y Z
    #1 A1 4 4 3
    #2 B2 4 4 1
    #3 C3 5 8 6
    

    数据

    responses <- structure(list(ID = c("A1", "B2", "C3"), X1 = c(1L, 0L, 3L), 
        X2 = c(1L, 1L, 3L), X3 = c(2L, 3L, 2L), X4 = c(1L, 0L, 0L
        )), class = "data.frame", row.names = c(NA, -3L))
    
    key <- structure(list(X = 2:4, Y = 1:3, Z = c(1L, 2L, 4L)), class = "data.frame",
       row.names = c(NA, 
    -3L))
    

    【讨论】:

    • 我的“关键”data.frame 中包含 NA(某些量表使用更多响应)。我认为这会导致“未定义的列”错误。有没有办法解决这个问题?
    【解决方案2】:

    这是处理此问题的另一种方法。我只是想用我最喜欢的解决方案来挑战自己,这并不像亲爱的@akrun 提出的那样简洁和出色。这是他教我如何使用purrr 函数家族的人:

    library(dplyr)
    library(purrr)
    
    responses %>% 
      select(X1:X4) %>% 
      pmap_dfr(., ~ map_dfc(1:length(key), function(x) sum(c(...)[key[, x]]))) %>%
      bind_cols(responses$ID) %>%
      set_names(c("x", "y", "z", "ID")) %>% 
      relocate(ID)
    
      ID        x     y     z
      <chr> <int> <int> <int>
    1 A1        4     4     3
    2 B2        4     4     1
    3 C3        5     8     6
    

    亲爱的@akrun 提出了两种更简洁的方法,我想在这里补充一下。一个带有rowSums 功能,另一个带有reduce 来自purrr 包。请记住,当我们将 + 函数与 reduce 应用于数据框时,它将应用于每一行并将其折叠为单个元素:

    map_dfc(key, ~ responses[-1][.x] %>% rowSums())
    
    # A tibble: 3 x 3
          X     Y     Z
      <dbl> <dbl> <dbl>
    1     4     4     3
    2     4     4     1
    3     5     8     6
    

    还有reduce:

    map_dfc(key, ~ responses[-1][.x] %>% reduce(`+`))
    
    # A tibble: 3 x 3
          X     Y     Z
      <int> <int> <int>
    1     4     4     3
    2     4     4     1
    3     5     8     6
    

    【讨论】:

    • 我认为 rowSums 方法更直接,或者您可以将reduce+ 一起使用,即map_dfc(key, ~ responses[-1][.x] %&gt;% reduce(+))
    • 你一如既往的正确。现在让我试试这种方法,因为我现在正在练习我的reduce 功能技能哈哈。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多