【问题标题】:dplyr collapse by rank of variable but ignore NAdplyr 按变量等级折叠但忽略 NA
【发布时间】:2019-01-22 01:42:54
【问题描述】:

我正在为我的数据崩溃而苦苦挣扎。

基本上,我的数据由多个指标和每年的多个观察值组成。我想将其转换为针对每个国家/地区的每个指标的一个观察结果。

我有一个排名指标,它指定必须选择观察的顺序。

基本上必须选择具有第一等级的观察(因此 1 而不是 2),只要该等级的值不是 NA。

另一个问题:我的数据集中的年份随时间而变化,因此有没有办法使代码动态化,因为它将代码应用于从 1990 年到 2025 年存在的所有列名?

df <- data.frame(country.code = c(1,1,1,1,1,1,1,1,1,1,1,1), 
                        id = as.factor(c("GDP", "GDP", "GDP", "GDP", "CA", "CA", "CA", "GR", "GR", "GR", "GR", "GR")), 
                       `1999` = c(NA,NA,NA, 1000,NA,NA, 100,NA,NA, NA,NA,22), 
                       `2000` = c(NA,NA,1, 2,NA,1, 2,NA,1000, 12,13,2), 
                       `2001` = c(3,100,1, 3,100,20, 1,1,44, 65,NA,NA),
                       rank = c(1, 2 , 3 , 4 , 1, 2, 3, 1, 3, 2, 4, 5))

结果应该是以下数据集:

    result <- data.frame(country.code = c(1, 1, 1), 
                         id = as.factor(c("GDP", "CA", "GR")),
                         `1999`= c(1000, 100, 22),
                         `2000`= c(1, 1, 12),
                         `2001`= c(3, 100, 1))

我尝试了以下解决方案(但考虑到数据中的 NA,这不起作用,我必须指定每一列:

    test <- df %>% group_by(Country.Code, Indicator.Code) %>% 
                summarise(test1999 = `1999`[which.min(rank))

我不明白如何解释 R 以省略 1999 列中为 NA 的情况。

【问题讨论】:

    标签: r dplyr summarize


    【解决方案1】:

    这是一个选项,它使用tidyr::fillNAs 替换为第一个非NA 值,然后我们将arranged 数据通过idrank 替换。这可能不是最有效的方法,因为我们首先gather,然后再次spread 数据。

    library(tidyverse)
    df %>% 
      arrange(id, rank) %>% 
      gather(key, value, X1999:X2001) %>% 
      tidyr::fill(value, .direction = "up") %>% 
      spread(key, value) %>% 
      group_by(id) %>% 
      slice(1) %>% 
      ungroup()
    # A tibble: 3 x 6
    #  country.code id     rank X1999 X2000 X2001
    #         <dbl> <fct> <dbl> <dbl> <dbl> <dbl>
    #1            1 CA        1   100     1   100
    #2            1 GDP       1  1000     1     3
    #3            1 GR        1    22    12     1
    

    注意:列名可能不是 19992000 等,如您的数据中那样。但这很容易被采用。

    【讨论】:

      【解决方案2】:

      您可以将数据框更改为长格式,删除 na,选择与最小排名相对应的值并传播回宽格式

       library(tidyr)
        test <- df %>%
        gather("Year", "Value", X1999:X2001) %>%
        filter(!is.na(Value))%>%
        group_by(country.code, id, Year) %>% 
        arrange(rank)%>%
        summarise(first(Value)) %>%
        spread(Year, `first(Value)`)
      

      【讨论】:

        【解决方案3】:

        我们可以使用列的非空值的最小等级进行子集化,例如x[rank==min(rank[!is.na(x)])]

        另一个问题:我的数据集中的年份随时间而变化,......

        使用summarise_atvarsmatches 可以使用正则表达式[0-9]{4} 选择任何4 位数字的列名,即1990-2025(这意味着搜索重复的数字“0-9”正好 4 次)并使用funs 对它们应用上述过程

        librar(dplyr)    
        df %>% group_by(country.code,id) %>% 
               summarise(`1999` = `1999`[rank==ifelse(all(is.na(`1999`)),1, min(rank[!is.na(`1999`)]))])
        
        df %>% group_by(country.code,id) %>% 
               summarise_at(vars(matches("[0-9]{4}")),funs(.[rank==ifelse(all(is.na(.)), 1, min(rank[!is.na(.)]))]))
        
         # A tibble: 3 x 5
         # Groups:   country.code [?]
          country.code id    `1999` `2000` `2001`
                 <dbl> <fct>  <dbl>  <dbl>  <dbl>
        1            1 CA       100      1    100
        2            1 GDP     1000      1      3
        3            1 GR        22     12      1
        

        【讨论】:

        • 感谢您的解决方案。但是,一旦一年中没有“id”之一的数据,它就不再起作用了。当您将 1999 列替换为 1999 = c(NA,NA,NA, NA,NA,NA, 100,NA,NA, NA,NA,22) 时,它不再起作用。任何对此都有效的解决方案?
        • @Jan-Pieter 感谢您指出这一点。请检查我的更新答案。
        • 感谢分配!像魅力一样工作!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-21
        • 1970-01-01
        • 2013-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多