【问题标题】:Transform data.frame with repeated A-column values to a transposed data.frame将具有重复 A 列值的 data.frame 转换为转置的 data.frame
【发布时间】:2020-06-20 00:37:32
【问题描述】:

我有一个银行 Excel,它给了我这样的信息:

A        B         C
Name     XYZ       trash
Date     20/05/31  trash
Amount   trash     0.01
Name     ABC       trash
Date     20/06/30  trash
Amount   trash     0.02
Name     KLM       trash
Date     20/07/29  trash
Amount   trash     -0.03

我想要的结果是:

Name  Date      Amount
XYZ   20/05/31  0.01
ABC   20/06/30  0.02
KLM   20/07/29  -0.03

为了清理 df,我使用了:

sel_col <- c("Name" = 2, "Date" = 2, "Amount" = 3)
df <- df %>%
  mutate(D = sel_col[match(df$A, names(sel_col))]) %>% 
  mutate(E = recode(D, A, B, C)) %>% 
  select(A, E)

如何拆分和转置?这是最好的方法吗?

Ps:使用 readxl,我收到以下警告:“未知或未初始化的列:'Data'”

【问题讨论】:

  • 非常感谢!所有答案都解决了我的问题。我不清楚“垃圾”这个词。它不是垃圾这个词,而是一些不重要的数据或没有数据。真的很喜欢@a5c1d2h2i1m1n2o1r2t1 的简短回答,但因为它是一个 Excel 数据,总是可以有一些问题(例如“金额”加倍),我将使用来自@ronak-shah 的group_by/pivot_wider/ungroup 组合,如果pivot_wider 函数出现问题,我会报错

标签: r dataframe dplyr split tidyverse


【解决方案1】:

这是一种使用data.table的方法:

library(data.table)
x[C != "trash", `:=`(B, C)][, dcast(.SD, rowid(A) ~ A, value.var = "B")]
##    A Amount     Date Name
## 1: 1   0.01 20/05/31  XYZ
## 2: 2   0.02 20/06/30  ABC
## 3: 3  -0.03 20/07/29  KLM

这里是“x”:

 x <- structure(list(A = c("Name", "Date", "Amount", "Name", "Date",                             
     "Amount", "Name", "Date", "Amount"), B = c("XYZ", "20/05/31",                               
     "trash", "ABC", "20/06/30", "trash", "KLM", "20/07/29", "trash"                             
     ), C = c("trash", "trash", "0.01", "trash", "trash", "0.02",                                
     "trash", "trash", "-0.03")), row.names = c(NA, 
     9L), class = c("data.table", "data.frame"))  

【讨论】:

    【解决方案2】:

    我们可以获取长格式数据,删除'trash'值,创建一个出现'Name'值的组,获取宽格式数据。

    library(dplyr)
    library(tidyr)
    
    df %>%
      pivot_longer(cols = -A) %>%
      filter(value != 'trash') %>%
      select(-name) %>%
      group_by(grp = cumsum(A == 'Name')) %>%
      pivot_wider(names_from = A, values_from = value) %>%
      ungroup %>%
      select(-grp) %>% type.convert(as.is = TRUE)
    
    
    # A tibble: 3 x 3
    #  Name  Date     Amount
    #  <chr> <chr>     <dbl>
    #1 XYZ   20/05/31   0.01
    #2 ABC   20/06/30   0.02
    #3 KLM   20/07/29  -0.03
    

    【讨论】:

      【解决方案3】:

      试试这个:

      df %>%
        mutate_all(~ if_else(. == "trash", NA_character_, .)) %>%
        mutate(
          grp = cumsum(A == "Name"),
          B = coalesce(B, C)
        ) %>%
        select(-C) %>%
        pivot_wider(grp, names_from = A, values_from  = B) %>%
        mutate(
          Date = as.Date(Date, format = "%y/%m/%d"),
          Amount = as.numeric(Amount)
        ) %>%
        select(-grp)
      # # A tibble: 3 x 3
      #   Name  Date       Amount
      #   <chr> <date>      <dbl>
      # 1 XYZ   2020-05-31   0.01
      # 2 ABC   2020-06-30   0.02
      # 3 KLM   2020-07-29  -0.03
      

      假设:

      • 每 3 组行总是以 "Name" 开头;和
      • BC有可用的数据,而不是两者。

      (我假设您希望 Date 成为 R 中的实际日期类...如果您希望将其保留为字符串,请省略它。)

      【讨论】:

        猜你喜欢
        • 2022-01-02
        • 2020-11-22
        • 2015-01-06
        • 2019-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-18
        相关资源
        最近更新 更多