【问题标题】:Fill numeric variable while preserving group在保留组的同时填充数字变量
【发布时间】:2018-10-20 01:14:43
【问题描述】:

[编辑以反映更好的例子]

假设我有一个这样的数据框:

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

如何在保留x 的同时将year 增加1?我想填写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

但是,这与所需的输出不匹配。

【问题讨论】:

  • 修改数据的解决方案将更加简单。只需tidyr::complete 就足够了。看看我的回答。

标签: r dataframe dplyr tidyverse


【解决方案1】:

使用tidyr::completedplyr::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

【讨论】:

    【解决方案2】:

    使用基础 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
    

    【讨论】:

    • 我的例子不足以代表我的实际问题。我已经在上面进行了修改。想法?
    【解决方案3】:

    我们可以先splitx,然后为每个x组创建一个year向量,加入每个组dffill向下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
    

    【讨论】:

    • 我不得不修改我的问题,因为它没有准确解决我的现实问题。见上文。
    【解决方案4】:

    这是一个非常简单的基本 R 方法,带有 tapplystack

    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
    

    【讨论】:

      猜你喜欢
      • 2011-03-15
      • 2014-12-10
      • 1970-01-01
      • 2022-11-27
      • 2018-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多