【问题标题】:Condense Dataframe压缩数据框
【发布时间】:2020-06-20 17:44:46
【问题描述】:

这个如何压缩:

Date    AAPL   MSFT NASDAQ
1.1.19  NA     NA   NA
2.1.19  2%     NA   5%
3.1.19  3%     NA   6%
...
1.1.19  NA     NA   NA
2.1.19  NA     4%   5%
3.1.19  NA     5%   6%
...

看起来像:

Date    AAPL   MSFT NASDAQ
1.1.19  NA     NA   NA
2.1.19  2%     4%   5%
3.1.19  3%     5%   6%
...

是否有没有重复日期和纳斯达克值的功能,删除NAs?

谢谢!

【问题讨论】:

    标签: dataframe r dataframe na data-cleaning


    【解决方案1】:

    我们可以使用summarise_all(假设每一列的每个“日期”只有一个非NA元素)

    library(dplyr)
    df %>%
       group_by(Date) %>%
       summarise_all(na.omit)
    

    如果我们有多个非 NA 元素,并且在某些情况下只有 NA,请创建 list 列或 paste

    df %>%
        group_by(Date) %>%
        summarise_at(vars(-group_cols()), ~ list(if(all(is.na(.))) .[n() + 1] else .[!is.na(.)]))
    # A tibble: 3 x 4
    #  Date   AAPL      MSFT      NASDAQ   
    #  <chr>  <list>    <list>    <list>   
    #1 1.1.19 <chr [1]> <chr [1]> <chr [1]>
    #2 2.1.19 <chr [1]> <chr [1]> <chr [2]>
    #3 3.1.19 <chr [1]> <chr [1]> <chr [2]>
    

    另外,如果某些元素是重复的,那么我们采用unique 并假设每组没有完全不同的元素

    df %>%
        group_by(Date) %>%
        summarise_at(vars(-group_cols()), ~ if(all(is.na(.))) .[n() + 1] else unique(.[!is.na(.)]))
    # A tibble: 3 x 4
    #  Date   AAPL  MSFT  NASDAQ
    #  <chr>  <chr> <chr> <chr> 
    #1 1.1.19 <NA>  <NA>  <NA>  
    #2 2.1.19 2%    4%    5%    
    #3 3.1.19 3%    5%    6%  
    

    或者先做distinct再做分组操作

    distinct(df) %>% 
          group_by(Date) %>% 
          summarise_at(vars(-group_cols()), ~ .[!is.na(.)][1])
    # A tibble: 3 x 4
    #  Date   AAPL  MSFT  NASDAQ
    #  <chr>  <chr> <chr> <chr> 
    #1 1.1.19 <NA>  <NA>  <NA>  
    #2 2.1.19 2%    4%    5%    
    #3 3.1.19 3%    5%    6%   
    

    或者在dplyrdevel版本中,我们可以使用condense

    df %>% 
         group_by(Date) %>% 
         condense(data = across(everything(),  ~ .[!is.na(.)]))
    # A tibble: 3 x 2
    # Rowwise:  Date
    #  Date   data            
    #  <chr>  <list>          
    #1 1.1.19 <tibble [0 × 3]>
    #2 2.1.19 <tibble [2 × 3]>
    #3 3.1.19 <tibble [2 × 3]>
    

    数据

    df <- structure(list(Date = c("1.1.19", "2.1.19", "3.1.19", "1.1.19", 
    "2.1.19", "3.1.19"), AAPL = c(NA, "2%", "3%", NA, NA, NA), MSFT = c(NA, 
    NA, NA, NA, "4%", "5%"), NASDAQ = c(NA, "5%", "6%", NA, "5%", 
    "6%")), class = "data.frame", row.names = c(NA, -6L))
    

    【讨论】:

    • 感谢您的回答。不幸的是,您的代码不会压缩数据框。我已经调整了上面的最小示例以更好地反映我的情况。
    • @Ben 你的意思是这两种方法都不起作用?你能分享更多关于你关心的信息吗? list 应将元素保留在 list 中,即每个“日期”保留 1 行
    • @Ben 我根据您的示例更新了帖子。我猜其中一个与您显示的输出相同。但是,我也会保留其他选项以防您的数据集。更通用
    【解决方案2】:

    以下是一些基本的 R 解决方案:

    • 使用split + rbind
    dfout <- do.call(rbind,
                     c(make.row.names = F,
                       Map(function(z) data.frame(Map(function(x) ifelse(all(is.na(x)),NA,na.omit(x)),z)),
                           split(df,df$Date))))
    
    • 使用ave + unique
    dfout <- unique(cbind(df[1],
                          sapply(df[-1],
                                 function(q) ave(q,df$Date,FUN = function(x) ifelse(all(is.na(x)),NA,na.omit(x))))))
    

    这样

    > dfout
        Date AAPL MSFT NASDAQ
    1 1.1.19 <NA> <NA>   <NA>
    2 2.1.19   2%   4%     5%
    3 3.1.19   3%   5%     6%
    

    数据

    df <- structure(list(Date = c("1.1.19", "2.1.19", "3.1.19", "1.1.19", 
    "2.1.19", "3.1.19"), AAPL = c(NA, "2%", "3%", NA, NA, NA), MSFT = c(NA, 
    NA, NA, NA, "4%", "5%"), NASDAQ = c(NA, "5%", "6%", NA, "5%", 
    "6%")), class = "data.frame", row.names = c(NA, -6L))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多