dplyr 滞后与列值中的 n

Posted

技术标签:

【中文标题】dplyr 滞后与列值中的 n【英文标题】:dplyr lag with n from column values 【发布时间】:2018-08-28 08:08:40 【问题描述】:

是否可以在 dplyr::lag 函数中使用列值作为 n

可重现的例子:

DF <- data.frame(
    V = runif(1000, min=-100, max=100), 
    nlag = as.integer(runif(1000, min=1, max=10))
) %>% 
mutate(Vlag = lag(V, n = nlag))

我得到这个错误:

错误:评估错误:n 必须是非负整数标量,而不是长度为 1000 的整数。

还有其他选择吗?

更新:

我们如何在小组内解决相同的问题?

可重现的例子:

DF <- data.frame(
    V = runif(1000, min=-100, max=100),
    nlag = as.integer(runif(1000, min=1, max=10)),
    type = sample(1:4, replace=TRUE)
) %>%
group_by(type) %>% 
mutate(Vlag = lag(V, n = nlag))

【问题讨论】:

【参考方案1】:

?lag 的文档说

n 长度为 1 的正整数,给出领先或落后的位置数

所以不可能给出任何大于 length = 1 的数字。

但是,我们可以通过用相应的nlag 值减去当前行索引来生成索引以获取V 值,然后我们使用该索引来获取滞后的V 值。

df$lag_value <- sapply(seq_along(df$nlag), function(x) 
      indx = x - df$nlag[x]
     if(indx > 0)
        df$V[indx]
     else
        NA
)
df

#          V nlag lag_value
#1  51.30453    6        NA
#2 -66.33709    4        NA
#3  95.45096    9        NA
#4  44.54434    3  51.30453
#5  62.00180    3 -66.33709
#6 -18.43012    4 -66.33709

更新

如果我们想按组执行此操作,我们可以按type 列拆分它们并应用相同的操作。

df$lag_value <- unlist(lapply(split(df, df$type), function(x) 
        sapply(seq_along(x$nlag), function(y) 
          indx = y - x$nlag[y]
          if(indx > 0)
            x$V[indx]
          else
             NA
)))

数据

df <- head(DF)

【讨论】:

【参考方案2】:

nlag 的长度必须为 1,试试这样:

DF <- data.frame(
  V = runif(1000, min=-100, max=100), 
  nlag = as.integer(runif(1000, min=1, max=10))
) %>%  mutate(Vlag = V[if_else((row_number() - nlag) < 1, as.integer(NA), row_number() - nlag)])
                V nlag         Vlag
1     -6.72598341    4           NA
2    -84.67472238    2           NA
3     -4.98048104    7           NA
4      2.64957272    4           NA
5     82.16284532    4  -6.72598341
6     28.93483448    9           NA
7     88.16730371    3   2.64957272
8     42.31721302    7  -6.72598341
9    -38.12659876    1  42.31721302
10    74.62628153    3  88.16730371
...

【讨论】:

【参考方案3】:

另一个选项是使用purrr-package。 map2_dbl 将两个长度相同的向量(或列表)作为输入,并同时迭代它们。然后返回一个double。在map 调用中,V 的lag 使用指定的`nlag 计算,然后仅返回当前行。

library(dplyr)
library(purrr)

DF %>% 
  mutate(Vlag = map2_dbl(nlag, row_number(), ~ lag(V, n = .x)[.y]))

# A tibble: 20 x 3
#         V  nlag  Vlag
#     <dbl> <int> <dbl>
#  1  83.0      9  NA  
#  2  87.4      2  NA  
#  3 -42.8      9  NA  
#  4  66.1      9  NA  
#  5  28.3      1  66.1
#  6   3.82     5  83.0
#  7  47.3      4 -42.8
#  8 -73.1      9  NA  
#  9  31.4      5  66.1
# 10  41.0      8  87.4
# ...

数据 当使用随机数作为示例时,您应该指定一个种子。同样在这种情况下,较少的行数就足以显示问题。

set.seed(42)
DF <- tibble(V = runif(20, min=-100, max=100), 
             nlag = as.integer(runif(20, min=1, max=10))) 

【讨论】:

【参考方案4】:

我认为这比当前的答案要干净一些:

DF %>% 
  group_by(ID, nlag) %>% 
  mutate(Vlag = dplyr::lag(V, n = nlag[1])) %>%
  ungroup()

由于它是分组nlag,所有索引都是相同的,所以取第一个就可以了。

【讨论】:

以上是关于dplyr 滞后与列值中的 n的主要内容,如果未能解决你的问题,请参考以下文章

使用正则表达式删除Mysql中列值中的括号()

(Python)如何修复数据框列值中的数值表示错误

如何从 SQL 中的列值中提取特定部分(Redshift 平台)

R/dplyr:使用循环创建滞后并根据列名计算累积总和

dplyr 动态创建滞后和 ma 特征

如何从SQL中的列值中提取特定部分(Redshift平台)