首页 > 解决方案 > 保留上一年的行

问题描述

我只是想试一试,因为我知道这里有一些聪明的人可能有一个 r 代码。我将无法自己编写代码。

所以我得到了一个数据集,其中包含 2000-01 和 2008-12 之间的名称和年月。看起来像这样:

 Name      Date
 A         2000-01
 A         2000-02
 A          ...
 A         2008-12
 A         2000-01
 B         2000-01
 B          ...
 B         2008-12
 C         and so on..

可能发生的情况是,对于我的键列中的每个名称,每年都有一个值。这是我能要求的最好的。不幸的是,有些年份在我的关键列中没有价值。在我的数据集中进一步了解仅查看名称 A:

因此,如果我在 2000 年至 2008 年之间的每一年都没有 1 个观察值,并且我想根据下一次观察的年份中的月份从年份和月份中获取对我的键列没有值的行。在这个例子中:

2003-02 对我的 keycolumn 有一个值,而 2002-02 没有,我想从日期 2002-02 和名称 A 中取回该行。简而言之:“根据来自上一年的键列保留上一年的行明年”

有一些简单的方法来编码吗?谢谢 :)

标签: excel

解决方案


没有直接简单的方法来编码您所描述的内容,但当然可以将问题分解为更简单的部分。问题的核心部分如下。给定具有非 NA 值的行的数据框,例如

  year month
1 2002    12
2 2005    11
3 2006    01
4 2008    07

对于每一行,检查数据框以查看上一年是否存在;如果是,则返回该行,如果否,则返回上一年和同月的附加行。这是一个可能看起来像的函数

check_ym <- function(y, m, dat) {
  if ((y - 1) %in% dat$year) {
    return(data.frame(Date = paste(y, m, sep = "-"), stringsAsFactors = FALSE))
  } else {
    return(data.frame(Date = paste(c(y - 1, y), c(m, m), sep = "-"), stringsAsFactors = FALSE))
  }
}

现在,让我们制作一些假数据。

library(dplyr)
library(tidyr)
library(purrr)

# Simulate data
set.seed(123)
x <- data.frame(Date = paste(sample(2000:2008, 4),
                             sprintf("%02d", sample(1:12, 4, replace = TRUE)),
                             sep = "-"),
                KeyColumn = floor(runif(4, 1, 10)))
d <- data.frame(Date = paste(rep(2000:2008, each = 12),
                             sprintf("%02d", rep(1:12, times = 9)),
                             sep = "-")) %>%
  left_join(x)

识别非 NA 行:

dd <- d %>%
  na.omit() %>%
  separate(Date, into = c("year", "month")) %>%
  mutate(year = as.numeric(year))
dd
#   year month KeyColumn
# 1 2002    12         5
# 2 2005    11         5
# 3 2006    01         5
# 4 2008    07         9

然后,我们运行上面的函数,遍历yearmonth列。这给了我们

out <- map2_df(dd$year, dd$month, .f = check_ym, dat = dd)
out
#      Date
# 1 2001-12
# 2 2002-12
# 3 2004-11
# 4 2005-11
# 5 2006-01
# 6 2007-07
# 7 2008-07

最后,我们将其与原始数据结合起来:

inner_join(out, d)
# Joining, by = "Date"
#      Date KeyColumn
# 1 2001-12        NA
# 2 2002-12         5
# 3 2004-11        NA
# 4 2005-11         5
# 5 2006-01         5
# 6 2007-07        NA
# 7 2008-07         9

这只是为了一个Name。我们也可以对许多Names 执行此操作。首先创建一些假数据:

# Simulate data
set.seed(123)
d <- map_df(setNames(1:3, LETTERS[1:3]), function(...) {
  x <- data.frame(Date = paste(sample(2000:2008, 4),
                               sprintf("%02d", sample(1:12, 4, replace = TRUE)),
                               sep = "-"),
                  KeyColumn = floor(runif(4, 1, 10)))
  data.frame(Date = paste(rep(2000:2008, each = 12),
                               sprintf("%02d", rep(1:12, times = 9)),
                               sep = "-")) %>%
    left_join(x)
}, .id = "Name")
dd <- d %>%
  na.omit() %>%
  separate(Date, into = c("year", "month")) %>%
  mutate(year = as.numeric(year))
dd
#    Name year month KeyColumn
# 1     A 2002    12         5
# 2     A 2005    11         5
# 3     A 2006    01         5
# 4     A 2008    07         9
# 5     B 2000    04         6
# 6     B 2004    01         7
# 7     B 2005    12         9
# 8     B 2006    03         9
# 9     B 2000    04         6
# 10    C 2003    12         1
# 11    C 2005    04         7
# 12    C 2006    11         5
# 13    C 2008    02         8

现在,使用split将数据帧拆分为三个数据帧Name;对于每个子数据框,我们应用check_ym(),然后我们将结果组合在一起并将其与原始数据连接:

lapply(split(dd, dd$Name), function(dat) {
  map2_df(dat$year, dat$month, .f = check_ym, dat = dat)
}) %>%
  bind_rows(.id = "Name") %>%
  inner_join(d)
# Joining, by = c("Name", "Date")
#    Name    Date KeyColumn
# 1     A 2001-12        NA
# 2     A 2002-12         5
# 3     A 2004-11        NA
# 4     A 2005-11         5
# 5     A 2006-01         5
# 6     A 2007-07        NA
# 7     A 2008-07         9
# 8     B 2000-04         6
# 9     B 2003-01        NA
# 10    B 2004-01         7
# 11    B 2005-12         9
# 12    B 2006-03         9
# 13    C 2002-12        NA
# 14    C 2003-12         1
# 15    C 2004-04        NA
# 16    C 2005-04         7
# 17    C 2006-11         5
# 18    C 2007-02        NA
# 19    C 2008-02         8

推荐阅读