Преобразование data.frame с повторяющимися значениями A-столбца в транспонированный data.frame - PullRequest
1 голос
/ 20 июня 2020

У меня есть банковский 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)

Как это разделить и транспонировать? И это лучший способ go?

Ps: Используя readxl, я получаю это предупреждение: «Неизвестный или неинициализированный столбец: 'Данные'»

Ответы [ 3 ]

2 голосов
/ 20 июня 2020

Вот подход с использованием 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"))  
1 голос
/ 20 июня 2020

Мы можем получить данные в длинном формате, удалить '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
1 голос
/ 20 июня 2020

Попробуйте следующее:

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

Допущения:

  • каждый пакет из трех строк всегда начинается с "Name"; и
  • есть полезные данные в либо B, либо C, но не в обоих.

(я предполагал, что вы хотите, чтобы Date был фактический класс даты в R ... опустите это, если вы предпочитаете сохранить его в виде строки.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...