嵌套 for 循环替代方案,用于将每个 ID 的值与上一年的值进行比较

问题描述 投票:0回答:3

我有一个包含 45k 多行的数据框,其中包含 ID

SE441
和年份
NUM_EXPLOTACION
的变量
ANO
的值。

我想计算每年和上一年之间每个ID的变量差异。问题是某些 ID 缺少年份,因此使用

lag
函数似乎不是我的解决方案。

我想要实现的一个例子是:

ANO  NUM_EXPLOTACION  SE441  diff
2017             657     12    NA
2018             657     15     3
2020             657     13    NA
2018             123      1    NA
2019             123      4     3
2020             123      0    -4

示例数据框:

macro <- data.frame(ANO=c(2017, 2018, 2020, 2018, 2019, 2020),
                    NUM_EXPLOTACION=c(657, 657, 657, 123, 123, 123), 
                    SE441=c(12, 15, 13, 1, 4, 0))

这是一个嵌套的 for 循环,我相信它可以完成这项工作,但它花费的时间太长,因此不可行:

for (i in min(macro$NUM_EXPLOTACION):max(macro$NUM_EXPLOTACION)) {
  for (j in min(macro$ANO) + 1:max(macro$ANO)) {
    macro$diff[macro$NUM_EXPLOTACION == i & macro$ANO == j] <- 
      if (length(macro$SE441[macro$NUM_EXPLOTACION == i & macro$ANO == j - 1])) {
        macro$SE441[macro$NUM_EXPLOTACION == i & macro$ANO == j] - 
          macro$SE441[macro$NUM_EXPLOTACION == i & macro$ANO == j - 1]
      } else NA
  }
}

在上面的代码中,我使用

min(macro$ANO) + 1
来避免尝试使用不存在的值(第一个值之前没有上一年)进行数学计算,并且
if(length(...))
仅在存在匹配的 ID 和上一年时才执行该函数。

有什么想法吗?

r for-loop lag
3个回答
0
投票

您可以使用

complete()
中的
tidyr
来填充
SE441
中缺失值的所有年份 ID 组合,然后滞后应该起作用:

macro <- data.frame(ANO=c(2017,2018,2020,2018,2019,2020), 
                    NUM_EXPLOTACION=c(657,657,657,123,123,123), 
                    SE441=c(12,15,13,1,4,0))
library(tidyverse)
macro %>% 
  mutate(orig = 1) %>% 
  complete(ANO, NUM_EXPLOTACION, fill=list(SE441 = NA, orig=0)) %>% 
  arrange(NUM_EXPLOTACION, ANO) %>% 
  group_by(NUM_EXPLOTACION) %>% 
  mutate(diff = SE441-lag(SE441)) %>% 
  filter(orig==1)
#> # A tibble: 6 × 5
#> # Groups:   NUM_EXPLOTACION [2]
#>     ANO NUM_EXPLOTACION SE441  orig  diff
#>   <dbl>           <dbl> <dbl> <dbl> <dbl>
#> 1  2018             123     1     1    NA
#> 2  2019             123     4     1     3
#> 3  2020             123     0     1    -4
#> 4  2017             657    12     1    NA
#> 5  2018             657    15     1     3
#> 6  2020             657    13     1    NA

创建于 2024-05-23,使用 reprex v2.0.2


0
投票

一种选择是

merge
expand.grid
并使用
diff
按组计算
ave

> macro |> 
+   merge(expand.grid(ANO=min(macro$ANO):max(macro$ANO),
+                     NUM_EXPLOTACION=unique(macro$NUM_EXPLOTACION)), all=TRUE) |>
+   sort_by(~ NUM_EXPLOTACION + ANO) |>  ## requires R >= 4.4.0
+   transform(diff=ave(SE441, NUM_EXPLOTACION, FUN=\(x) c(NA, diff(x))))
   ANO NUM_EXPLOTACION SE441 diff
1 2017             123    NA   NA
3 2018             123     1   NA
5 2019             123     4    3
7 2020             123     0   -4
2 2017             657    12   NA
4 2018             657    15    3
6 2019             657    NA   NA
8 2020             657    13   NA

0
投票

使用连接的方法。首先加入已完成的年份,然后在

SE441
上使用 diff,最后重新加入原始年份以删除缺失的年份

library(dplyr)

full_join(macro, macro %>% 
                   reframe(ANO = min(ANO):max(ANO), .by = NUM_EXPLOTACION), 
    by = c("ANO", "NUM_EXPLOTACION")) %>% 
  arrange(NUM_EXPLOTACION, ANO) %>% 
  mutate(diff = c(NA, diff(SE441)), .by = NUM_EXPLOTACION) %>% 
  right_join(macro, by = c("ANO", "NUM_EXPLOTACION", "SE441"))
   ANO NUM_EXPLOTACION SE441 diff
1 2018             123     1   NA
2 2019             123     4    3
3 2020             123     0   -4
4 2017             657    12   NA
5 2018             657    15    3
6 2020             657    13   NA
© www.soinside.com 2019 - 2024. All rights reserved.