【问题标题】:Tidy Data: Rename columns, get non-NA column names, then gather整洁的数据:重命名列,获取非 NA 列名,然后收集
【发布时间】:2024-01-01 11:25:01
【问题描述】:

我有一些相当难看的数据需要整理,需要帮助!我的数据现在是什么样子的:

countries <- c("Austria", "Belgium", "Croatia")

df <- tibble("age" = c(28,42,19, 67),
         "1_recreate_1"=c(NA,15,NA,NA), 
         "1_recreate_2"=c(NA,10,NA,NA), 
         "1_recreate_3"=c(NA,8,NA,NA),
         "1_recreate_4"=c(NA,4,NA,NA),
         "1_fairness" = c(NA, 7, NA, NA),
         "1_confidence" = c(NA, 5, NA, NA),
         "2_recreate_1"=c(29,NA,NA,30),
         "2_recreate_2"=c(20,NA,NA,24),
         "2_recreate_3"=c(15,NA,NA,15),
         "2_recreate_4"=c(11,NA,NA,9),
         "2_fairness" = c(4, NA, NA, 1),
         "2_confidence" = c(5, NA, NA, 4),
         "3_recreate_1"=c(NA,NA,50,NA), 
         "3_recreate_2"=c(NA,NA,40,NA), 
         "3_recreate_3"=c(NA,NA,30,NA),
         "3_recreate_4"=c(NA,NA,20,NA),
         "3_fairness" = c(NA,  NA, 2, NA),
         "3_confidence" = c(NA, NA, 2, NA),
         "overall" = c(3,3,2,5))    

我需要它们最终的样子(硬编码):

df <- tibble(age = rep(c(28,42,19,67), each=4),
         country = rep(c("Belgium", "Austria", "Croatia", "Belgium"), each=4),
         recreate = rep(1:4, times=4),
         fairness = rep(c(4,7,2,1), each=4),
         confidence = rep(c(5,5,2,4), each=4),     
         allocation = c(29, 20, 15, 11,
                        15, 10, 8, 4,
                        50, 40, 30, 20, 
                        30, 24, 15, 9),
         overall = rep(c(3,3,2,5), each=4))

到达那里的步骤(我想!):

1.使用我的国家/地区列表替换这些列的起始数字。
开始字符串的数字是countries 中的索引。换句话说,16_recreate_1 将对应于向量countries 中的第 16 个国家/地区。我认为以下代码有效(虽然不确定它是否完全正确):

for(i in length(countries):1){
    colnames(df) <- str_replace(colnames(df), paste0(i,"_"), paste0(countries[i],"_"))
}  

2。通过获取每行的非 NA 列的名称来创建一个名为“country”的新变量。

我对@9​​87654327@ 和names 进行了一系列实验,但无法完全发挥作用。

3.创建新变量 (recreate_1...recreate_4) 以获取每一行的 [country_name]_recreate_1...[country_name]_recreate_4 值,无论该人的国家/地区是非 NA。

也许rowSums 是这样做的方法?

4.使数据长而不是宽 我认为这将需要gather,但我不确定如何仅从变量countryrecreate_1...recreate_4 中收集。

很抱歉,这太复杂了。 Tidyverse 解决方案是首选,但非常感谢任何帮助!

【问题讨论】:

  • 糟糕!对此感到抱歉--已更新。

标签: r tidyr stringr dplyr


【解决方案1】:

tidyverse 的某种不同的可能性可能是:

df %>%
 gather(variable, allocation, na.rm = TRUE) %>%
 separate(variable, c("ID", "variable", "recreate"), convert = TRUE) %>%
 left_join(data.frame(countries) %>%
            mutate(country = countries,
                   ID = seq_along(countries)) %>%
            select(-countries), by = c("ID" = "ID")) %>%
 select(-variable, -ID) 

   recreate allocation country
      <int>      <dbl> <fct>  
 1        1         15 Austria
 2        2         10 Austria
 3        3          8 Austria
 4        4          4 Austria
 5        1         29 Belgium
 6        1         30 Belgium
 7        2         20 Belgium
 8        2         24 Belgium
 9        3         15 Belgium
10        3         15 Belgium
11        4         11 Belgium
12        4          9 Belgium
13        1         50 Croatia
14        2         40 Croatia
15        3         30 Croatia
16        4         20 Croatia

在这里,首先将数据从宽格式转换为长格式,删除带有 NA 的行。其次,它将变量名称分成三列。第三,它将国家的向量转换为df,并为每个国家分配一个唯一的ID。最后将两者连接起来,去掉多余的变量。

已编辑问题的解决方案:

df %>%
 select(matches("(recreate)")) %>%
 rowid_to_column() %>%
 gather(var, allocation, -rowid, na.rm = TRUE) %>%
 separate(var, c("ID", "var", "recreate"), convert = TRUE) %>%
 select(-var) %>%
 left_join(data.frame(countries) %>%
            mutate(country = countries,
                   ID = seq_along(countries)) %>%
            select(-countries), by = c("ID" = "ID")) %>% 
 left_join(df %>%
            select(-matches("(recreate)")) %>%
            rowid_to_column() %>%
            gather(var, val, -rowid, na.rm = TRUE) %>%
            mutate(var = gsub("[^[:alpha:]]", "", var)) %>%
            spread(var, val), by = c("rowid" = "rowid")) %>%
 select(-rowid, -ID)

   recreate allocation country   age confidence fairness overall
      <int>      <dbl> <fct>   <dbl>      <dbl>    <dbl>   <dbl>
 1        1         15 Austria    42          5        7       3
 2        2         10 Austria    42          5        7       3
 3        3          8 Austria    42          5        7       3
 4        4          4 Austria    42          5        7       3
 5        1         29 Belgium    28          5        4       3
 6        1         30 Belgium    67          4        1       5
 7        2         20 Belgium    28          5        4       3
 8        2         24 Belgium    67          4        1       5
 9        3         15 Belgium    28          5        4       3
10        3         15 Belgium    67          4        1       5
11        4         11 Belgium    28          5        4       3
12        4          9 Belgium    67          4        1       5
13        1         50 Croatia    19          2        2       2
14        2         40 Croatia    19          2        2       2
15        3         30 Croatia    19          2        2       2
16        4         20 Croatia    19          2        2       2

在这里,首先选择包含recreate 的列并添加一个具有行ID 的列。其次,它遵循原始解决方案的步骤。第三,它选择不包含recreate 的列,执行从宽到长的数据转换,从列名中删除数字并将数据转换回原始宽格式。最后,它在行 ID 上连接两者并删除冗余变量。

【讨论】:

    【解决方案2】:
    library(dplyr)
    library(tidyr)
    df %>% mutate(rid=row_number()) %>% 
           gather(key,val,-c(age,overall,rid, matches('recreate'))) %>% mutate(country=sub('(^\\d)_.*','\\1',key),country=countries[as.numeric(country)]) %>% 
           filter(!is.na(val)) %>% mutate(key=sub('(^\\d\\_)(.*)','\\2',key)) %>%
           spread(key,val) %>% gather(key = recreate,value = allocation,-c(rid,age,overall,Country,confidence,fairness)) %>% 
           filter(!is.na(allocation)) %>% mutate(recreate=sub('.*_(\\d$)','\\1',recreate))
    

    这里(^\\d)_.* 表示获取第一个数字,而.*_(\\d$) 表示获取最后一个数字。

    【讨论】:

    • 这真是令人印象深刻——如此高效。谢谢,苏利曼!
    • 2 Qs: 1. 我有大约十几个变量(例如nameage 等)在1_recreate_1 列表之后和之后的另外十几个变量...带有此代码。如何将它们保存在新的 gathered 数据中? 2. 我还调用了变量1_confidence1_fairness,我想做与1_recreate_1 相同的事情,但它们不以_# 结尾。如何获取这些(创建一个名为confidencefairness 的新变量)?我把这两个都排除在我原来的问题之外,以为我会弄明白的,但我迷失在sub 和正则表达式中。我编辑了原件。
    最近更新 更多