Заполнить числовую переменную при сохранении группы - PullRequest
0 голосов
/ 09 мая 2018

[отредактировано для лучшего примера]

Скажем, у меня есть такой фрейм данных:

df <- data.frame(x = c("A","A","B", "B"), year = c(2001,2004,2002,2005))

> df
  x year
1 A 2001
2 A 2004
3 B 2002
4 B 2005

Как я могу увеличить year на 1, сохранив x? Я хотел бы заполнить year так, чтобы последовательность была такой:

  x year
1 A 2001
2 A 2002
3 A 2003
4 A 2004
5 B 2002
6 B 2003
7 B 2004
8 B 2005

Кто-нибудь может порекомендовать хороший способ сделать это?

@ useR рекомендую этот подход:

> data.frame(year = min(df$year):max(df$year)) %>%
   full_join(df) %>%
   fill(x) 
Joining, by = "year"
  year x
1 2001 A
2 2002 B
3 2003 B
4 2004 A
5 2005 B

Однако это не соответствует желаемому результату.

Ответы [ 4 ]

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

Вот довольно простой метод base R с tapply и stack.

stack(tapply(df$year, df["x"], function(x) min(x):max(x)))

Здесь tapply делит вектор года на группы df$x и затем строит последовательность от минимального до максимального года. Возвращает именованный список, который подается на stack для получения следующего.

  values ind
1   2001   A
2   2002   A
3   2003   A
4   2004   A
5   2002   B
6   2003   B
7   2004   B
8   2005   B

Если вам интересно, как вы можете сделать это в data.table, это также довольно просто:

library(data.table)
setDT(df)[, .(year=min(year):max(year)), by=x]

, который возвращает

   x year
1: A 2001
2: A 2002
3: A 2003
4: A 2004
5: B 2002
6: B 2003
7: B 2004
8: B 2005
0 голосов
/ 09 мая 2018

Сначала мы можем split на x, затем создать вектор year для каждой группы x, объединиться с каждой группой df, fill вниз x, а затем, наконец, rbind все группа df вместе.

library(dplyr)
library(tidyr)

df %>%
  split(.$x) %>%
  lapply(function(y) data.frame(year = min(y$year):max(y$year)) %>%
  full_join(y) %>%
  fill(x)) %>%
  unname() %>%
  do.call(rbind, .)

Результат:

  year x
1 2001 A
2 2002 A
3 2003 A
4 2004 A
5 2002 B
6 2003 B
7 2004 B
8 2005 B
0 голосов
/ 10 мая 2018

Опцией использования tidyr::complete и dplyr::lead может быть:

library(tidyverse)

df <- data.frame(x = LETTERS[1:3], year = c(2001,2004,2007))  

df %>% mutate(nextYear = ifelse(is.na(lead(year)),year, lead(year)-1)) %>%
  group_by(x) %>%
  complete(year = seq(year, nextYear, by=1)) %>% 
  select(-nextYear) %>%
  as.data.frame()

#   x year
# 1 A 2001
# 2 A 2002
# 3 A 2003
# 4 B 2004
# 5 B 2005
# 6 B 2006
# 7 C 2007

Отредактировано: Решение для измененных данных

df <- data.frame(x = c("A","A","B", "B"), year = c(2001,2004,2002,2005))
library(tidyverse)
df %>%  group_by(x) %>%
  complete(year = seq(min(year), max(year), by=1)) %>% 
  as.data.frame()


#   x year
# 1 A 2001
# 2 A 2002
# 3 A 2003
# 4 A 2004
# 5 B 2002
# 6 B 2003
# 7 B 2004
# 8 B 2005
0 голосов
/ 09 мая 2018

Использование базы R (с небольшой помощью от zoo):

full_df = data.frame(year = min(df$year):max(df$year))
df = merge(df, full_df, all = TRUE)
df = df[order(df$year), ]
df$x = zoo::na.locf(df$x)
df
#   year x
# 1 2001 A
# 2 2002 A
# 3 2003 A
# 4 2004 B
# 5 2005 B
# 6 2006 B
# 7 2007 C

Использование "Tidyverse"

df <- data.frame(x = LETTERS[1:3], year = c(2001,2004,2007))
library(dplyr)
library(tidyr)
df = df %>% mutate(year = factor(year, levels = min(year):max(year))) %>%
    complete(year) %>%
    fill(x) %>%
    mutate(year = as.numeric(as.character(year)))
df
# # A tibble: 7 x 2
#    year      x
#   <dbl> <fctr>
# 1  2001      A
# 2  2002      A
# 3  2003      A
# 4  2004      B
# 5  2005      B
# 6  2006      B
# 7  2007      C
...