Изменить данные из длинного в широкий формат - PullRequest
1 голос
/ 30 мая 2019

Я ищу быстрый способ преобразования данных из длинного в широкий формат. Прямо сейчас я попробовал код с гнездом для циклов, хотя работа выполнена, генерация вывода занимает много времени.

SN NN EE Service_tier
A  B  C  economy
B  C  C  economy
P  Q  R  regular
Q  S  R  regular
S  R  R  regular
H  I  L  economy
I  J  L  economy
J  K  L  economy
K  L  L  economy

Ожидаемый результат как ниже

SN hop1 hop2 hop3 hop4 service_tier
A   B    C              economy
P   Q    S    R         regular
H   I    J    K    L    economy

В настоящее время приведенный ниже код выполняет свою работу. Я уверен, что есть эффективный и чистый способ сделать это.

for (i in 1:lasrow){
  sn <- raw_d[i,1]
  nn <- raw_d[i,2]
  en <- raw_d[i,3]

  lc <- 1

  if(nn == en){
    d[lr,lc]<-sn
    d[lr,lc+1]<-nn
    d[lr,lc+2]<-en
    lr <- lr+1
  }
  else{
    while(nn!=en){
      d[lr,lc]<-sn
      lc <- lc+1
      next_d <- filter(raw_d,raw_d$SN==sn,raw_d$EN==en)
      if(dim(next_d)[1]==0){
        d[lr,lc]<-"broken bf"
        lc <- lc+1
        break
      }else{
        sn <- next_d$NN
        nn <- next_d$NN
        }
      }
    d[lr,lc]<-en
    lr<-lr+1
  }
}

Ответы [ 3 ]

0 голосов
/ 30 мая 2019

Мы можем использовать data.table.Преобразуйте файл «data.frame» в «dat.table» (setDT(df1), сгруппированный по rleid в «Service_tier», измените значение «SN» на first элемент, сгруппированный по «grp», затем сгруппированный по'Service_tier', 'SN', получить элемент unique Подмножества Data.table и dcast из формата 'long' в 'wide'

library(data.table)
dcast(setDT(df1)[, SN := first(SN), rleid(Service_tier)][, 
    unique(unlist(.SD)), .(SN, Service_tier)], 
    SN + Service_tier ~ paste0("hop", rowid(SN)), value.var = "V1", fill = "")
#  SN Service_tier hop1 hop2 hop3 hop4
#1:  A      economy    B    C          
#2:  H      economy    I    J    K    L
#3:  P      regular    Q    S    R     

data

df1 <- structure(list(SN = c("A", "B", "P", "Q", "S", "H", "I", "J", 
"K"), NN = c("B", "C", "Q", "S", "R", "I", "J", "K", "L"), EE = c("C", 
"C", "R", "R", "R", "L", "L", "L", "L"), Service_tier = c("economy", 
"economy", "regular", "regular", "regular", "economy", "economy", 
"economy", "economy")), class = "data.frame", row.names = c(NA, 
-9L))
0 голосов
/ 30 мая 2019

Важным моментом здесь является определение того, какие строки принадлежат какой группе. Ответы Ronak и akrun оба используют rleid(Service_tier), предполагая, что изменение Service_tier указывает на начало новой группы.

Это может быть предложено образцом набора данных, но не может считаться гарантированным. ИМХО, Service_tier скорее атрибут, чем ключ. Фактически, OP проверяет наличие NN == EE в своем фрагменте кода, чтобы переключиться на новую группу.

В приведенных ниже решениях для data.table группировка определяется с помощью cumsum(shift(NN == EE, fill = TRUE)), который проверяет равенство fo NN и EE, переносит результат в следующую строку, где начинается следующая группа, и перечисляет группы путем подсчета TRUE с использованием cumsum().

В упрощенном варианте (без изменения формы) прыжки агрегируются функцией toString():

library(data.table)
setDT(d)[, .(SN = first(SN), hops = toString(NN), Service_tier = first(Service_tier)), 
  by = .(grp = cumsum(shift(NN == EE, fill = TRUE)))][]
   grp SN       hops Service_tier
1:   1  A       B, C      economy
2:   2  P    Q, S, R      regular
3:   3  H I, J, K, L      economy

Для преобразования из длинного в широкий формат используется dcast():

library(data.table)
library(magrittr)   # piping used to improve readability
w <- setDT(d)[, .(SN = first(SN), hops = NN, Service_tier = first(Service_tier)), 
  by = .(grp = cumsum(shift(NN == EE, fill = TRUE)))] %>% 
  dcast(grp + ... ~ rowid(grp, prefix = "hop"), value.var = "hops", fill = "")  %>%  
  setcolorder(c(1:2, 4:ncol(.), 3))

w
   grp SN hop1 hop2 hop3 hop4 Service_tier
1:   1  A    B    C                economy
2:   2  P    Q    S    R           regular
3:   3  H    I    J    K    L      economy

setcolorder() используется для перестановки столбцов в порядке, ожидаемом OP. Это делается на месте , т.е. без копирования всего объекта данных.

Данные

library(data.table)

d <- fread("SN NN EE Service_tier
A  B  C  economy
B  C  C  economy
P  Q  R  regular
Q  S  R  regular
S  R  R  regular
H  I  L  economy
I  J  L  economy
J  K  L  economy
K  L  L  economy")
0 голосов
/ 30 мая 2019

Один из вариантов - создать уникальную последовательность, используя rleid из data.table, gather кадра данных в длинном формате, удалить дубликаты из каждой группы, назначить имена столбцов и spread вернуть их в широкоформатный формат.

library(dplyr)
library(tidyr)

df %>%
  mutate(row = data.table::rleid(Service_tier)) %>%
  gather(key, value, -Service_tier, -row) %>%
  group_by(row) %>%
  filter(!duplicated(value)) %>%
  mutate(key = c("SN", paste0("hop", 1:(n() - 1)))) %>%
  spread(key, value) %>%
  ungroup() %>%
  select(-row) %>%
  select(SN, starts_with("hop"), Service_tier)

# A tibble: 3 x 6
#  SN    hop1  hop2  hop3  hop4  Service_tier
#  <chr> <chr> <chr> <chr> <chr> <fct>       
#1  A     B     C     NA    NA    economy     
#2  H     I     J     K     L     economy     
#3  P     Q     S     R     NA    regular    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...