问题描述
我不能解决这个问题。
我有一个不完整的数据集(许多行和变量),其中一个因素指定了所有其他变量是前后的。我需要获取所有前后变量的摘要统计信息,包括pre-和post-value都不为NA的行。
如果每个变量的集合都不完整,我试图寻找一种用NA替换现有值的方法。
以下是我要实现的目标的简单示例:
df = data.frame(
id = c(1,1,2,2),myfactor = as.factor(c(1,2)),var2change = c(10,10,NA,20),var3change = c(5,15,var4change = c(NA,3,8)
)
导致:
id myfactor var2change var3change var4change
1 1 1 10 5 NA
2 1 2 10 10 2
3 2 1 NA 15 3
4 2 2 20 20 8
我想要的输出是:
id myfactor var2change var3change var4change
1 1 1 10 5 NA
2 1 2 10 10 NA
3 2 1 NA 15 3
4 2 2 NA 20 8
我要处理的变量不止一个,并且对于每个变量,该集合都不完整,而且方式不同。我感觉这可以通过巧妙地使用plyr / tidyr软件包中的现有功能来实现,但是我找不到一种将这些概念应用于我的问题的优雅方法。
任何帮助将不胜感激。
解决方法
您可以按id
分组,如果其中包含NA
的任何值都用NA
替换它们。要将函数应用于多个列,我们使用across
。
library(dplyr)
df %>%
group_by(id) %>%
mutate(across(starts_with('var'),~if(any(is.na(.))) NA else .))
#for dplyr < 1.0.0 we can use `mutate_at`
#mutate_at(vars(starts_with('var')),~if(any(is.na(.))) NA else .)
# id myfactor var2change var3change var4change
# <dbl> <fct> <dbl> <dbl> <dbl>
#1 1 1 10 5 NA
#2 1 2 10 10 NA
#3 2 1 NA 15 3
#4 2 2 NA 20 8
,
我假设您拥有的数据集是有序的,所以每对观察都按其行索引分组。
默认情况下,如果mean()
函数的任何输入为NA
,它将返回一个NA
。因此,这是一种使用NA
按组获取dplyr
的好方法。
library(dplyr)
df = data.frame(
myfactor = as.factor(c(1,2,1,2)),var2change = c(10,10,NA,20)
)
# 1 Create ID variable to group rows in pairs
id = c()
j = 0
for (i in 1:length(df$var2change)){
k = floor(j/2)
id = c(id,k)
j = j + 1
}
df$id = id
# Set all variables within group to NA if one of them is
df = df %>%
group_by(id) %>%
mutate(var_changed = mean(var2change))
如果您的数据中有一个明确的ID变量,则可以替换此解决方案的第一部分。
编辑:对多个变量执行此操作(基于对问题的更改):
df = data.frame(
id = c(1,2),myfactor = as.factor(c(1,20),var3change = c(5,15,var4change = c(NA,3,8)
)
for (col in 2:4) {
col = paste0("var",col,"change")
df = df %>%
group_by(id) %>%
mutate(new_col = mean(get(col)))
df[["new_col"]] = ifelse(is.na(df["new_col"]),df[[col]])
df[col] = NULL
names(df)[names(df) == "new_col"] <- col
}
如果速度是一个问题,则可以通过将group_by
移到循环之外来加快速度
拥有分组变量(group
)和时间变量(myfactor
)会很有帮助。然后,您可以使用dplyr
进行一些整理,以创建所需的变量。
library(dplyr)
df = data.frame(
group = rep(c(1,each = 2),20)
)
df %>% group_by(group) %>%
mutate(var3change = all(!is.na(var2change)),var4change = if_else(var3change,var2change,as.numeric(NA)))