Сложный фрейм данных и транспонировать данные - PullRequest
0 голосов
/ 31 мая 2018

У меня есть фрейм данных, как показано ниже:

ID  Capital  Instal  Date1 Date2
2    500      25      a     b
2    500      20      a     c
2    450      15      a     a
2    300      10      a     f
2    250       0      a     z
4    100      25      b     a
4    90       20      b     b
4    80       15      b     a
4    75       10      b     f
4    25        0      b     z

Я хочу создать новый data.frame из этого, где, если Date1=Date2, то мой новый фрейм данных B будет выглядеть какодин ниже:

ID  Date1  Capital  Instal1  Instal2  Instal3  Instal4
2     a     450       15       10       0
4     b      90       20       15       10       0

Поэтому я хочу, чтобы новый data.frame рассматривал данные только после того, как Date1 и Date2 равны.

Ответы [ 3 ]

0 голосов
/ 31 мая 2018

Вот еще одно tidyverse решение ...

library(dplyr)
library(tidyr)

df2 <- df %>% 
  group_by(ID) %>%   #group by ID
  mutate(ind=cumsum(Date1==Date2)) %>%  #mark elements after first Date1==Date2
  filter(ind!=0) %>%  #remove previous elements
  summarise(Date1=first(Date1),
            Capital=first(Capital),
            Instal=list(Instal)) %>%  #capture values for table
  unnest() %>%  #spread Instal, one value per row
  group_by(ID) %>% 
  mutate(Inst=paste0("Instal",row_number())) %>%  #mark names of Instal values
  spread(key=Inst,value=Instal)  #spread into wide format

df2
     ID Date1 Capital Instal1 Instal2 Instal3 Instal4
1     2     a     450      15      10       0      NA
2     4     b      90      20      15      10       0
0 голосов
/ 31 мая 2018

tidyverse

Вот подход tidyverse (dplyr + tidyr):

library(tidyverse)
df2 <- df %>%
  group_by(ID) %>%
  filter(cumsum(Date1 == Date2) >0) %>%
  transmute(Capital=Capital[1],Instal,Date1,colnames = paste0("Instal",seq(n()))) %>%
  ungroup %>%
  spread(colnames,Instal)

df2[is.na(df2)] <- 0 # omit if you'd rather have NA
# # A tibble: 2 x 7
#      ID Capital Date1 Instal1 Instal2 Instal3 Instal4
# * <int>   <int> <chr>   <int>   <int>   <int>   <int>
# 1     2     450     a      15      10       0       0
# 2     4      90     b      20      15      10       0

Вызов filter удаляет строки передDate1 == Date2

С transmute мы сохраняем только необходимые столбцы и создаем имена столбцов, которые будем распространять.Мы устанавливаем все значения Capital на первое, так как это единственное, что нам нужно.ID сгруппирован, поэтому он сохраняется по умолчанию и не разрешен в transmute.

Затем мы ungroup и создаем учебник spread

base R

В базе R мы можем использовать split и reshape и следовать тем же идеям, с небольшим утомительным переформатированием в конце для заполнения более узких субфреймов.

df_list <- 
lapply(split(df,df$ID),function(x) {
  x <- subset(x,cumsum(Date1==Date2)>0)
  x <- transform(x, Capital=Capital[1], time = seq(nrow(x)))
  reshape(x,idvar=c("ID","Capital","Date1"),direction="wide",sep="",drop="Date2")
})
all_names <- names(df_list[[which.max(lengths(df_list))]])
df_list_full <- lapply(df_list,function(x) {x[setdiff(all_names,names(x))] <- NA;x})
do.call(rbind, df_list_full)

#   ID Capital Date1 Instal1 Instal2 Instal3 Instal4
# 2  2     450     a      15      10       0      NA
# 4  4      90     b      20      15      10       0

данные:

df <- read.table(text = "ID  Capital  Instal  Date1 Date2
                2    500      25      a     b
                2    500      20      a     c
                2    450      15      a     a
                2    300      10      a     f
                2    250       0      a     z
                4    100      25      b     a
                4    90       20      b     b
                4    80       15      b     a
                4    75       10      b     f
                4    25        0      b     z",h=T,strin=F)
0 голосов
/ 31 мая 2018

Немного окольным путем.Я уверен, что есть более быстрый способ сделать это, но он дает вам именно то, что вы ожидаете в качестве вывода.

Шаги: когда date1 == date2 выберите row_number и заполните его после выбора.Отфильтруйте эти записи и выберите только нужные столбцы.создайте столбец, который будет использоваться в качестве заголовков в распространении, и распространите данные Instal.затем присоедините подмножество данных, чтобы получить правильное значение Capital, и объедините эту таблицу с предыдущим выбором.

library(dplyr)
library(tidyr)

df %>%
  group_by(ID) %>% 
  mutate(rowid = row_number(),
         selection = ifelse(Date1 == Date2, rowid, NA)) %>% 
  fill(selection) %>% # fill rowid over the rows after date1 == date2
  filter(!is.na(selection)) %>% 
  select(ID, Date1, Instal) %>% 
  mutate(Installation = paste0("Instal", row_number())) %>% 
  spread(Installation, Instal) %>% 
  inner_join(df %>% filter(Date1 == Date2) %>% select(ID, Date1, Capital), .)

  ID Date1 Capital Instal1 Instal2 Instal3 Instal4
1  2     a     450      15      10       0      NA
2  4     b      90      20      15      10       0

data:

df <- structure(list(ID = c(2L, 2L, 2L, 2L, 2L, 4L, 4L, 4L, 4L, 4L), 
    Capital = c(500L, 500L, 450L, 300L, 250L, 100L, 90L, 80L, 
    75L, 25L), Instal = c(25L, 20L, 15L, 10L, 0L, 25L, 20L, 15L, 
    10L, 0L), Date1 = c("a", "a", "a", "a", "a", "b", "b", "b", 
    "b", "b"), Date2 = c("b", "c", "a", "f", "z", "a", "b", "a", 
    "f", "z")), class = "data.frame", row.names = c(NA, -10L))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...