Добавить строку в кадр данных на основе условия предыдущей строки в R - PullRequest
3 голосов
/ 29 марта 2020

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

class <- c(3,0,3,0,0)
value <- c(50,50,70,30,100)
days <- c(3,3,2,2,1)
mydata <- data.frame(class, value, days)

Мне нужно, чтобы на каждый день были представлены оба класса - так что если в данный день нет класса 3 (в этом примере , день 1) Я бы хотел добавить строку, где class = 3 и value = 0 и day = 1. Мои реальные данные более сложны, потому что для каждого дня есть различное количество строк (и гораздо больше дней, чем 3) и много других столбцов (но для которых было бы хорошо ввести NA). Это не кажется слишком сложной проблемой, но у меня возникают проблемы, когда я оборачиваюсь вокруг кода. Спасибо!

Ответы [ 2 ]

3 голосов
/ 29 марта 2020

Используя tidyverse, вы можете использовать complete:

library(tidyverse)

mydata %>%
  complete(days, class, fill = list(value = 0))

Выход

# A tibble: 6 x 3
   days class value
  <dbl> <dbl> <dbl>
1     1     0   100
2     1     3     0
3     2     0    30
4     2     3    70
5     3     0    50
6     3     3    50

Данные

mydata <- structure(list(class = c(3, 0, 3, 0, 0), value = c(50, 50, 70, 
30, 100), days = c(3, 3, 2, 2, 1)), class = "data.frame", row.names = c(NA, 
-5L))
0 голосов
/ 29 марта 2020

С base R мы можем сделать

out <- merge(expand.grid(lapply(mydata[c('class', 'days')],
         unique)), mydata, all.x = TRUE)
out$value[is.na(out$value)] <- 0
out
#  class days value
#1     0    1   100
#2     0    2    30
#3     0    3    50
#4     3    1     0
#5     3    2    70
#6     3    3    50

ПРИМЕЧАНИЕ: пакеты не используются


Или с data.table

library(data.table)
setDT(mydata)[CJ(class, days, unique = TRUE),
     on = .(class, days)][is.na(value), value := 0][]
#   class value days
#1:     0   100    1
#2:     0    30    2
#3:     0    50    3
#4:     3     0    1
#5:     3    70    2
#6:     3    50    3

Или используя crossing/left_join из tidyverse

library(dplyr)
library(tidyr)
tidyr::crossing(class = unique(mydata$class),
       days = unique(mydata$days)) %>% 
  left_join(mydata) %>%
  mutate(value = replace_na(value, 0))
# A tibble: 6 x 3
#  class  days value
#  <dbl> <dbl> <dbl>
#1     0     1   100
#2     0     2    30
#3     0     3    50
#4     3     1     0
#5     3     2    70
#6     3     3    50

data

mydata <- structure(list(class = c(3, 0, 3, 0, 0), value = c(50, 50, 70, 
30, 100), days = c(3, 3, 2, 2, 1)), class = "data.frame", row.names = c(NA, 
-5L))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...