【问题标题】:Multiple columns processing and dynamically naming new columns多列处理和动态命名新列
【发布时间】:2017-06-05 15:18:48
【问题描述】:

变量被错误地输入多个列,例如:“aaa_1”、“aaa_2”和“aaa_3”,或“ccc_1”、“ccc_2”和“ccc_3”)。需要创建单个新列(例如“aaa” , 或 "ccc")。虽然某些变量目前在单个列中 ("hhh_1"),但可能会添加更多列 (hhh_2 等)。

这是我得到的:

aaa_1 <- c(43, 23, 65, NA, 45)  
aaa_2 <- c(NA, NA, NA, NA, NA)    
aaa_3 <- c(NA, NA, 92, NA, 82)  
ccc_1 <- c("fra", NA, "spa", NA, NA)   
ccc_2 <- c(NA, NA, NA, "wez", NA)  
ccc_3 <- c(NA, "ija", NA, "fda", NA)    
ccc_4 <- c(NA, NA, NA, NA, NA)
hhh_1 <- c(183, NA, 198, NA, 182)    
dataf1 <- data.frame(aaa_1,aaa_2,aaa_3,ccc_1,ccc_2, ccc_3,ccc_4,hhh_1)  

这就是我想要的:

aaa <- c(43, 23, NA, NA, NA)
ccc <- c("fra", "ija", "spa", NA, NA) 
hhh <- c(183, NA, 198, NA, 182)   
dataf2 <- data.frame(aaa,ccc,hhh)

需要通用解决方案,因为有大约 100 个变量(例如“aaa”、“hhh”、“ccc”、“ttt”、“eee”、“hhh”等)。

谢谢!

【问题讨论】:

    标签: r naming data-cleaning large-data


    【解决方案1】:

    这是一个基本解决方案,即没有包。

    首先定义get_only,当给定列表时将其转换为data.frame并将get_only应用于每一行。当给定一个向量时,它返回其中的单个非 NA,如果不只有一个,则返回 NA。

    root 定义为不带后缀的列名。

    将数据框转换为列列表,按root 对它们进行分组,并将get_only 应用于每个这样的组。

    最后,将结果列表转换为数据框。

    get_only <- function(x) UseMethod("get_only")
    get_only.list <- function(x) apply(data.frame(x), 1, get_only)
    get_only.default <- function(x) if (sum(!is.na(x)) == 1) na.omit(x) else NA
    
    root <- sub("_.*", "", names(dataf1))
    as.data.frame(lapply(split(as.list(dataf1), root), FUN = get_only))
    

    给予:

      age country hight
    1  43     fra   183
    2  23     ija    NA
    3  NA     spa   198
    4  NA    <NA>    NA
    5  NA    <NA>   182
    

    【讨论】:

    • 感谢您如此仔细地解释!
    【解决方案2】:

    我们可以试试splitstackshape

    library(splitstackshape)
    nm1 <- sub("_\\d+", "", names(dataf1))
    tbl <- table(nm1) > 1
    merged.stack(dataf1, var.stubs = names(tbl)[tbl], sep="_")
    

    【讨论】:

      【解决方案3】:

      我不确定您的示例是否正确。例如,在第三行中,您获得了 age_1 和 age_3 的值,然后在该行所需的输出 NA 中。

      如果我已经理解您要执行的操作,那么将列转置为行、修复它们然后再次转回会更容易。尝试使用 dplyr 和 tidyr 的“tidyverse”作为起点。

      library(tidyverse)
      library(stringr)
      
      age_1 <- c(43, 23, 65, NA, 45)
      age_2 <- c(NA, NA, NA, NA, NA)
      age_3 <- c(NA, NA, 92, NA, 82)
      country_1 <- c("fra", NA, "spa", NA, NA)
      country_2 <- c(NA, NA, NA, "wez", NA)
      country_3 <- c(NA, "ija", NA, "fda", NA)
      country_4 <- c(NA, NA, NA, NA, NA)
      hight_1 <- c(183, NA, 198, NA, 182)
      dataf1 <- data.frame(age_1,age_2,age_3,country_1,country_2, country_3,country_4,hight_1)
      
      data <- dataf1 %>%
        mutate(row_num = row_number()) %>%   #create a row number to track values
        gather(key, value, -row_num) %>%    #flatten your data
        drop_na() %>%    #drop na rows
        mutate(key = str_replace(key, "_.", "")) %>%   #remove the '_x' part of names
        group_by(row_num) %>%  
        top_n(1) %>%
        spread(key, value)  #pivot back to columns
      

      对于您的示例,您需要 group_by() 和 top_n() 行使其运行,因为您在同一行中有多个值。如果您只有一个值(我认为您应该这样做?),那么您可以删除这两行。没有它们会更好,因为如果您的数据错误,它将无法运行。

      编辑下面的评论。这将使任何重复的条目不适用。

      data <- dataf1 %>%
        mutate(row_num = row_number()) %>%   #create a row number to track values
        gather(key, value, -row_num) %>%    #flatten your data
        drop_na() %>%    #drop na rows
        mutate(key = str_replace(key, "_.", "")) %>%   #remove the '_x' part of names
        group_by(row_num, key) %>%
        mutate(count = n()) %>%  #count how many entries for each row/key combo
        mutate(value = ifelse(count > 1, NA, value)) %>%   #set NA for rows with duplicates
        drop_na() %>%
        spread(key, value) %>%  #pivot back to columns
        select(-count)  #drop the `count` variable 
      

      【讨论】:

      • 我想确保如果给定人的年龄同时输入为 65 (age_1) 和 92 (age_3),则输出为 NA(因为我无法确定哪个年龄是正确的,我希望能够估算该观察/行)。谢谢!
      • 在上面编辑了我的答案。您可以计算条目并删除任何重复的行
      猜你喜欢
      • 2015-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-30
      • 2021-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多