逐行替代引用前一行的 for 循环

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

我正在处理一些数据,我想创建一个列,其中下一行的值取决于上一行的值。 for 循环是我对此的第一个想法,但我正在处理的数据超过 600 万行,并且 for 循环需要 1 个多小时才能完成。

我正在寻找 for 循环的替代方案来完成此任务。数据的格式设置使我不相信 dplyr

lag()
能够满足我的需要。假设我有以下数据:

df = structure(list(x = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), y = c(0, 
1, 2, 3, 0, 1, 2, 3, 4, 5), z = c(5, NA, NA, NA, 6, NA, NA, NA, 
3, 2)), class = "data.frame", row.names = c(NA, -10L))

df$y
不是
NA
时,我想要一个新列
df$aa
来简单地返回
df$z
中的值。如果
df$y
确实是
NA
,我希望列
df$aa
只是最后一个非
NA
值。

这是我开发的for循环。它在处理少量数据时工作得很好,但正如前面提到的,处理 600 万行时速度太慢了。

for(i in 1:nrow(df)){
  if(!is.na(df$z[i])){
    df$aa[i] = df$z[i] 
  } else{
    df$aa[i] = df$aa[i-1]
  } 
}

此代码提供了所需的输出。非常感谢您的意见!

r
3个回答
1
投票

这应该快得多。本质上,逻辑是,如果

z
不是
NA
,则
aa <- z
。如果
z
NA
,我们使用
NA
的最后一个非
z
值,我们可以通过
data.table::nafill()
访问该值。

library(data.table)
setDT(df)

df[, aa := fifelse(
    !is.na(z),
    z,
    nafill(z, type = "locf")
)]

#         x     y     z    aa
#     <num> <num> <num> <num>
#  1:     1     0     5     5
#  2:     2     1    NA     5
#  3:     3     2    NA     5
#  4:     4     3    NA     5
#  5:     5     0     6     6
#  6:     6     1    NA     6
#  7:     7     2    NA     6
#  8:     8     3    NA     6
#  9:     9     4     3     3
# 10:    10     5     2     2

1
投票

可以使用

R
中的zoo包,它提供了
na.locf()
功能。此函数将
NA values
替换为最新的
non-NA value
。以下是如何将它与数据集一起使用:

library(zoo)

# Your data
df <- structure(list(x = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 
                     y = c(0, 1, 2, 3, 0, 1, 2, 3, 4, 5), 
                     z = c(5, NA, NA, NA, 6, NA, NA, NA, 3, 2)), 
                class = "data.frame", row.names = c(NA, -10L))

# Create column df$aa with NA values
df$aa <- NA

# Replace NA values in df$aa with the last non-NA value
df$aa <- ifelse(!is.na(df$z), df$z, na.locf(df$aa))

print(df)

这将为您提供所需的输出,其中

df$aa
包含每行
non-NA value
中的最后一个
df$z
,其中
df$y
NA
na.locf()
函数有效地向前传送最后一个
non-NA value
,避免了 for 循环的需要并显着提高了性能,尤其是对于像您这样的大型数据集。


0
投票

不是超级快而是短

df = structure(list(x = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
                    y = c(0, 1, 2, 3, 0, 1, 2, 3, 4, 5),
                    z = c(5, NA, NA, NA, 6, NA, NA, NA, 3, 2)), 
                    class = "data.frame", row.names = c(NA, -10L))


df$aa <- zoo::na.locf(df$z)
© www.soinside.com 2019 - 2024. All rights reserved.