簡體   English   中英

R - 如何以成對匹配的方式組合多個列中的值,可能使用“mutate”或“coalesce”?

[英]R - How can I combine values across multiple columns in a pairwise matching fashion, possibly using 'mutate' or 'coalesce'?

我有一個來自大型調查的數據集,其中包含約 2k 個參與者(行)和大約 160 個變量(列)。 相關欄目包括:

  • 參與者ID
  • cl.exp 這是一個“是”/“否”響應
  • cl.yes.Q1 到 cl.yes.Q7 如果參與者對 cl.exp 回答“是”,則其值為 NA,如果他們對 cl.exp 回答“否”,則為 NA
  • cl.no.Q1 到 cl.no.Q7 如果參與者對 cl.exp 回答“否”,則其值為 NA,如果他們對 cl.exp 回答“是”,則為 NA

cl.exp "yes" 和 "no" 的問題是同義詞,除了 no.Q6 和 no.Q7 是 yes.Q6 和 yes.Q7 的倒數; 即,no.Q7 與 yes.Q6 同義,no.Q6 與 yes.Q7 同義。

前幾行可能如下所示:

ID cl.exp cl.yes.Q1 cl.yes.Q2 cl.yes.Q3 cl.yes.Q4 cl.yes.Q5 cl.yes.Q6 cl.yes.Q7 分類號Q1 分類號Q2 分類號Q3 分類號Q4 分類號Q5 分類號Q6 分類號Q7
1 不適用 不適用 不適用 不適用 不適用 不適用 不適用 2 6 3 4 3 7 4
2 不適用 不適用 不適用 不適用 不適用 不適用 不適用 3 6 6 6 5 7 3
3 是的 2 5 6 6 4 2 7 不適用 不適用 不適用 不適用 不適用 不適用 不適用
4 是的 7 1 5 6 7 2 5 不適用 不適用 不適用 不適用 不適用 不適用 不適用

您會注意到參與者在 cl.yes.Q1-7 或 cl.no.Q1-7 中都有值,但從不會兩者都有。 我想執行以下任一操作:a) 將 cl.no.Q1-7 中的值移動到 cl.yes.Q1-7 的相應列中,或 b) 創建新列,將適當的列從cl.yes 和 cl.no,即 cl.yes.Q1 和 cl.no.Q1,cl.yes.Q2 和 cl.no.Q2,以此類推。

我使用以下代碼解決了 no.Q6 和 no.Q7 反向問題:

df[15:16] <- df[16:15]

然后我執行以下操作:

df.yes <- df %>% 
             select(contains("cl.yes"), id, cl.exp)  %>%
             drop_na()

df.no <- df %>% 
             select(contains("cl.no"), id, cl.exp)  %>%
             drop_na()

names(df.yes) <- gsub("cl.yes.", "cl.", names(df.yes))
names(df.no) <- gsub("cl.no.", "cl.", names(df.no))
df.cl <- merge(df.yes, df.no, all = TRUE)

這給了我一個包含合並列的新數據框。 但是,我相信一定有比這更簡單/更干凈/更優雅的解決方案,特別是能夠將數據保存在原始數據框中。 我嘗試了一些 mutate 和 coalesce 的迭代,但永遠不會成功。 如果有人有一兩行代碼基本上和我在這里做的事情一樣,我將非常感謝你的洞察力。 謝謝!

此解決方案使用 for 循環動態coalesce以相同問題編號結尾的列。 您需要知道最后一個問題編號才能記下 for 循環的迭代器。

library(dplyr)

dat2 <- dat %>% select(ID, cl.exp)

for (i in 1:7){
  temp <- dat %>% 
    select(ends_with(paste0("Q", i))) %>%
    as.list()
  
  dat2[[paste0("cl.Q", i)]] <- coalesce(!!!temp)
}

dat2
#   ID cl.exp cl.Q1 cl.Q2 cl.Q3 cl.Q4 cl.Q5 cl.Q6 cl.Q7
# 1  1     No     2     6     3     4     3     7     4
# 2  2     No     3     6     6     6     5     7     3
# 3  3    Yes     2     5     6     6     4     2     7
# 4  4    Yes     7     1     5     6     7     2     5

注意:我沒有交換 Q6 和 Q7,但我相信您已經找到了最好的方法。

數據

dat <- read.table(text = "ID    cl.exp  cl.yes.Q1   cl.yes.Q2   cl.yes.Q3   cl.yes.Q4   cl.yes.Q5   cl.yes.Q6   cl.yes.Q7   cl.no.Q1    cl.no.Q2    cl.no.Q3    cl.no.Q4    cl.no.Q5    cl.no.Q6    cl.no.Q7
1   No  NA  NA  NA  NA  NA  NA  NA  2   6   3   4   3   7   4
2   No  NA  NA  NA  NA  NA  NA  NA  3   6   6   6   5   7   3
3   Yes 2   5   6   6   4   2   7   NA  NA  NA  NA  NA  NA  NA
4   Yes 7   1   5   6   7   2   5   NA  NA  NA  NA  NA  NA  NA",
                  header = TRUE)

像這樣的東西怎么樣:

library(tidyverse)
dat <- tibble::tribble(~ID, ~cl.exp, ~cl.yes.Q1, ~cl.yes.Q2, ~cl.yes.Q3, ~cl.yes.Q4, ~cl.yes.Q5, ~cl.yes.Q6, ~cl.yes.Q7, ~cl.no.Q1, ~cl.no.Q2, ~cl.no.Q3, ~cl.no.Q4, ~cl.no.Q5, ~cl.no.Q6, ~cl.no.Q7, 
1, "No",NA,NA,NA,NA,NA,NA,NA,2,6,3,4,3,7,4,
2, "Yes",3,6,6,6,5,7,3, NA,NA,NA,NA,NA,NA,NA)

bind_cols(dat %>% select(c(ID, cl.exp)), 
          coalesce(dat %>% 
                     select(contains("no")) %>% 
                     setNames(gsub("\\.no", "", names(.))), 
                   dat %>% 
                     select(contains("yes"))%>% 
                     setNames(gsub("\\.yes", "", names(.)))))
#> # A tibble: 2 × 9
#>      ID cl.exp cl.Q1 cl.Q2 cl.Q3 cl.Q4 cl.Q5 cl.Q6 cl.Q7
#>   <dbl> <chr>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1     1 No         2     6     3     4     3     7     4
#> 2     2 Yes        3     6     6     6     5     7     3

reprex 包於 2022-06-10 創建 (v2.0.1)

我想你需要這個:

library(dplyr)
library(tidyr)

df %>% 
  pivot_longer(cols = -c(ID, cl.exp), 
               names_to = c('.value', 'name'), 
               names_pattern = '(.*)(\\d+)') %>% 
  mutate(cl.yes.Q = coalesce(cl.yes.Q, cl.no.Q), .keep="unused") %>% 
  pivot_wider(names_from = name, values_from = cl.yes.Q)
     ID cl.exp   `1`   `2`   `3`   `4`   `5`   `6`   `7`
  <int> <chr>  <int> <int> <int> <int> <int> <int> <int>
1     1 No         2     6     3     4     3     7     4
2     2 No         3     6     6     6     5     7     3
3     3 Yes        2     5     6     6     4     2     7
4     4 Yes        7     1     5     6     7     2     5

您應該能夠像這樣使用mutatecoalesce (在交換no.Q6no.Q7之后,如上所述):

library(dplyr)
result <- df %>% mutate(cl.Q1 = coalesce(cl.yes.Q1, cl.no.Q1), 
                        cl.Q2 = coalesce(cl.yes.Q2, cl.no.Q2), 
                        cl.Q3 = coalesce(cl.yes.Q3, cl.no.Q3), 
                        cl.Q4 = coalesce(cl.yes.Q4, cl.no.Q4), 
                        cl.Q5 = coalesce(cl.yes.Q5, cl.no.Q5), 
                        cl.Q6 = coalesce(cl.yes.Q6, cl.no.Q6), 
                        cl.Q7 = coalesce(cl.yes.Q7, cl.no.Q7)) %>%
                 select(-(cl.yes.Q1:cl.no.Q7))

我們只需使用mutate來創建cl.Q* * 列,分別合並來自cl.yes.Q*cl.no.Q*列的值。 然后,我們使用select刪除原始的cl.yes.Q*cl.no.Q*列。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM