dplyr 按变量等级折叠但忽略 NA
dplyr collapse by rank of variable but ignore NA
我正在为我的数据崩溃而苦苦挣扎。
基本上我的数据由多个指标组成,每年都有多个观察值。我想将其转换为针对每个国家/地区的每个指标的一个观察结果。
我有一个等级指示器,它指定必须按哪个顺序选择观察结果的顺序。
基本上必须选择排名第一(因此是 1 而不是 2)的观察值,只要该排名的值不是 NA。
另一个问题:我的数据集中的年份随时间变化,因此有没有一种方法可以使代码动态化,因为它将代码应用于从 1990 年到 2025 年存在的所有列名?
df <- data.frame(country.code = c(1,1,1,1,1,1,1,1,1,1,1,1),
id = as.factor(c("GDP", "GDP", "GDP", "GDP", "CA", "CA", "CA", "GR", "GR", "GR", "GR", "GR")),
`1999` = c(NA,NA,NA, 1000,NA,NA, 100,NA,NA, NA,NA,22),
`2000` = c(NA,NA,1, 2,NA,1, 2,NA,1000, 12,13,2),
`2001` = c(3,100,1, 3,100,20, 1,1,44, 65,NA,NA),
rank = c(1, 2 , 3 , 4 , 1, 2, 3, 1, 3, 2, 4, 5))
结果应该是以下数据集:
result <- data.frame(country.code = c(1, 1, 1),
id = as.factor(c("GDP", "CA", "GR")),
`1999`= c(1000, 100, 22),
`2000`= c(1, 1, 12),
`2001`= c(3, 100, 1))
我尝试了以下解决方案(但考虑到数据中的 NA,这不起作用,我必须指定每一列:
test <- df %>% group_by(Country.Code, Indicator.Code) %>%
summarise(test1999 = `1999`[which.min(rank))
我不明白如何解释 R 以忽略 1999 列中为 NA 的情况。
这是一个选项,它使用 tidyr::fill
将 NA
替换为第一个非 NA
值,之后我们将数据 arrange
d 设为 [=15] =] 和 rank
。这可能不是最有效的方法,因为我们首先 gather
然后再次 spread
数据。
library(tidyverse)
df %>%
arrange(id, rank) %>%
gather(key, value, X1999:X2001) %>%
tidyr::fill(value, .direction = "up") %>%
spread(key, value) %>%
group_by(id) %>%
slice(1) %>%
ungroup()
# A tibble: 3 x 6
# country.code id rank X1999 X2000 X2001
# <dbl> <fct> <dbl> <dbl> <dbl> <dbl>
#1 1 CA 1 100 1 100
#2 1 GDP 1 1000 1 3
#3 1 GR 1 22 12 1
注意:列名可能不是您的数据中的 1999
、2000
等。但这很容易被采用。
您可以将数据框更改为长格式,删除 na,select 对应于最小排名的值并展开回宽格式
library(tidyr)
test <- df %>%
gather("Year", "Value", X1999:X2001) %>%
filter(!is.na(Value))%>%
group_by(country.code, id, Year) %>%
arrange(rank)%>%
summarise(first(Value)) %>%
spread(Year, `first(Value)`)
我们可以使用列的非空值的最小等级进行子集,例如 x[rank==min(rank[!is.na(x)])]
。
An additional question: The years in my dataset vary over time,....
使用 summarise_at
、vars
和 matches
可用于 select 任何具有 4 位数字的列名称,即 1990-2025 使用正则表达式 [0-9]{4}
(这意味着搜索精确重复 4 次的数字“0-9”)并使用 funs
将上述过程应用于它们
librar(dplyr)
df %>% group_by(country.code,id) %>%
summarise(`1999` = `1999`[rank==ifelse(all(is.na(`1999`)),1, min(rank[!is.na(`1999`)]))])
df %>% group_by(country.code,id) %>%
summarise_at(vars(matches("[0-9]{4}")),funs(.[rank==ifelse(all(is.na(.)), 1, min(rank[!is.na(.)]))]))
# A tibble: 3 x 5
# Groups: country.code [?]
country.code id `1999` `2000` `2001`
<dbl> <fct> <dbl> <dbl> <dbl>
1 1 CA 100 1 100
2 1 GDP 1000 1 3
3 1 GR 22 12 1
我正在为我的数据崩溃而苦苦挣扎。
基本上我的数据由多个指标组成,每年都有多个观察值。我想将其转换为针对每个国家/地区的每个指标的一个观察结果。
我有一个等级指示器,它指定必须按哪个顺序选择观察结果的顺序。
基本上必须选择排名第一(因此是 1 而不是 2)的观察值,只要该排名的值不是 NA。
另一个问题:我的数据集中的年份随时间变化,因此有没有一种方法可以使代码动态化,因为它将代码应用于从 1990 年到 2025 年存在的所有列名?
df <- data.frame(country.code = c(1,1,1,1,1,1,1,1,1,1,1,1),
id = as.factor(c("GDP", "GDP", "GDP", "GDP", "CA", "CA", "CA", "GR", "GR", "GR", "GR", "GR")),
`1999` = c(NA,NA,NA, 1000,NA,NA, 100,NA,NA, NA,NA,22),
`2000` = c(NA,NA,1, 2,NA,1, 2,NA,1000, 12,13,2),
`2001` = c(3,100,1, 3,100,20, 1,1,44, 65,NA,NA),
rank = c(1, 2 , 3 , 4 , 1, 2, 3, 1, 3, 2, 4, 5))
结果应该是以下数据集:
result <- data.frame(country.code = c(1, 1, 1),
id = as.factor(c("GDP", "CA", "GR")),
`1999`= c(1000, 100, 22),
`2000`= c(1, 1, 12),
`2001`= c(3, 100, 1))
我尝试了以下解决方案(但考虑到数据中的 NA,这不起作用,我必须指定每一列:
test <- df %>% group_by(Country.Code, Indicator.Code) %>%
summarise(test1999 = `1999`[which.min(rank))
我不明白如何解释 R 以忽略 1999 列中为 NA 的情况。
这是一个选项,它使用 tidyr::fill
将 NA
替换为第一个非 NA
值,之后我们将数据 arrange
d 设为 [=15] =] 和 rank
。这可能不是最有效的方法,因为我们首先 gather
然后再次 spread
数据。
library(tidyverse)
df %>%
arrange(id, rank) %>%
gather(key, value, X1999:X2001) %>%
tidyr::fill(value, .direction = "up") %>%
spread(key, value) %>%
group_by(id) %>%
slice(1) %>%
ungroup()
# A tibble: 3 x 6
# country.code id rank X1999 X2000 X2001
# <dbl> <fct> <dbl> <dbl> <dbl> <dbl>
#1 1 CA 1 100 1 100
#2 1 GDP 1 1000 1 3
#3 1 GR 1 22 12 1
注意:列名可能不是您的数据中的 1999
、2000
等。但这很容易被采用。
您可以将数据框更改为长格式,删除 na,select 对应于最小排名的值并展开回宽格式
library(tidyr)
test <- df %>%
gather("Year", "Value", X1999:X2001) %>%
filter(!is.na(Value))%>%
group_by(country.code, id, Year) %>%
arrange(rank)%>%
summarise(first(Value)) %>%
spread(Year, `first(Value)`)
我们可以使用列的非空值的最小等级进行子集,例如 x[rank==min(rank[!is.na(x)])]
。
An additional question: The years in my dataset vary over time,....
使用 summarise_at
、vars
和 matches
可用于 select 任何具有 4 位数字的列名称,即 1990-2025 使用正则表达式 [0-9]{4}
(这意味着搜索精确重复 4 次的数字“0-9”)并使用 funs
librar(dplyr)
df %>% group_by(country.code,id) %>%
summarise(`1999` = `1999`[rank==ifelse(all(is.na(`1999`)),1, min(rank[!is.na(`1999`)]))])
df %>% group_by(country.code,id) %>%
summarise_at(vars(matches("[0-9]{4}")),funs(.[rank==ifelse(all(is.na(.)), 1, min(rank[!is.na(.)]))]))
# A tibble: 3 x 5
# Groups: country.code [?]
country.code id `1999` `2000` `2001`
<dbl> <fct> <dbl> <dbl> <dbl>
1 1 CA 100 1 100
2 1 GDP 1000 1 3
3 1 GR 22 12 1