我正在处理一些数据,我想创建一个列,其中下一行的值取决于上一行的值。 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]
}
}
此代码提供了所需的输出。非常感谢您的意见!
这应该快得多。本质上,逻辑是,如果
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
可以使用
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 循环的需要并显着提高了性能,尤其是对于像您这样的大型数据集。
不是超级快而是短
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)