[英]Group by and replace a value in group if two other values in group are NA
我有以下 df:
df <- data.frame(comp_name = c("A", "A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B"),
year = c("2016", "2016", "2016", "2017","2017", "2017", "2016","2016", "2016", "2017", "2017", "2017"),
indicator = c("total_revenue", "overseas_revenue", "domestic_revenue", "total_revenue", "overseas_revenue", "domestic_revenue","total_revenue", "overseas_revenue", "domestic_revenue","total_revenue", "overseas_revenue", "domestic_revenue"),
value = c(100, NA, NA, 100, 20, 80, 90, NA, 60, 90, NA, NA))
df 看起来像这样:
公司名称 | 年 | 指标 | 价值 |
---|---|---|---|
一种 | 2016年 | 总收入 | 100 |
一种 | 2016年 | 海外收入 | 北美 |
一种 | 2016年 | 国内收入 | 北美 |
一种 | 2017年 | 总收入 | 100 |
一种 | 2017年 | 海外收入 | 20 |
一种 | 2017年 | 国内收入 | 80 |
乙 | 2016年 | 总收入 | 90后 |
乙 | 2016年 | 海外收入 | 北美 |
乙 | 2016年 | 国内收入 | 60 |
乙 | 2017年 | 总收入 | 90后 |
乙 | 2017年 | 海外收入 | 北美 |
乙 | 2017年 | 国内收入 | 北美 |
我想按 comp_name 和年份分组并将以下规则应用于每个组:如果 overseas_revenue 和 domestic_revenue 的值为 NA,则将 domestic_revenue 的值设置为等于 total_revenue 的值,否则什么也不做。
生成的 df 应如下所示:
公司名称 | 年 | 指标 | 价值 |
---|---|---|---|
一种 | 2016年 | 总收入 | 100 |
一种 | 2016年 | 海外收入 | 北美 |
一种 | 2016年 | 国内收入 | 100 |
一种 | 2017年 | 总收入 | 100 |
一种 | 2017年 | 海外收入 | 20 |
一种 | 2017年 | 国内收入 | 80 |
乙 | 2016年 | 总收入 | 90后 |
乙 | 2016年 | 海外收入 | 北美 |
乙 | 2016年 | 国内收入 | 60 |
乙 | 2017年 | 总收入 | 90后 |
乙 | 2017年 | 海外收入 | 北美 |
乙 | 2017年 | 国内收入 | 90后 |
我的实际数据集有 500k + 行和 12 个不同的指标,但我一直无法找到有效的方法。 任何帮助将不胜感激-谢谢!
你可以用两个支点来做到这一点:
library(dplyr)
library(tidyr)
df <- data.frame(comp_name = c("A", "A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B"),
year = c("2016", "2016", "2016", "2017","2017", "2017", "2016","2016", "2016", "2017", "2017", "2017"),
indicator = c("total_revenue", "overseas_revenue", "domestic_revenue", "total_revenue", "overseas_revenue", "domestic_revenue","total_revenue", "overseas_revenue", "domestic_revenue","total_revenue", "overseas_revenue", "domestic_revenue"),
value = c(100, NA, NA, 100, 20, 80, 90, NA, 60, 90, NA, NA))
df %>%
pivot_wider(names_from="indicator",
values_from = "value") %>%
mutate(domestic_revenue = case_when(
is.na(overseas_revenue) & is.na(domestic_revenue) ~ total_revenue,
TRUE ~ domestic_revenue)) %>%
pivot_longer(-c(comp_name, year),
names_to = "indicator",
values_to = "value")
#> # A tibble: 12 × 4
#> comp_name year indicator value
#> <chr> <chr> <chr> <dbl>
#> 1 A 2016 total_revenue 100
#> 2 A 2016 overseas_revenue NA
#> 3 A 2016 domestic_revenue 100
#> 4 A 2017 total_revenue 100
#> 5 A 2017 overseas_revenue 20
#> 6 A 2017 domestic_revenue 80
#> 7 B 2016 total_revenue 90
#> 8 B 2016 overseas_revenue NA
#> 9 B 2016 domestic_revenue 60
#> 10 B 2017 total_revenue 90
#> 11 B 2017 overseas_revenue NA
#> 12 B 2017 domestic_revenue 90
由reprex package (v2.0.1) 创建于 2022-04-28
require(tidyverse)
df %>%
spread(indicator, value) %>%
mutate(domestic_revenue = case_when(
is.na(domestic_revenue) & is.na(overseas_revenue) ~ total_revenue,
TRUE ~ domestic_revenue
)) %>%
gather(c(-comp_name, -year), key = indicator, value = value) %>%
arrange(comp_name, year)
# A tibble: 12 x 4
comp_name year indicator value
<chr> <chr> <chr> <dbl>
1 A 2016 domestic_revenue 100
2 A 2016 overseas_revenue NA
3 A 2016 total_revenue 100
4 A 2017 domestic_revenue 80
5 A 2017 overseas_revenue 20
6 A 2017 total_revenue 100
7 B 2016 domestic_revenue 60
8 B 2016 overseas_revenue NA
9 B 2016 total_revenue 90
10 B 2017 domestic_revenue 90
11 B 2017 overseas_revenue NA
12 B 2017 total_revenue 90
我认为最好创建一个非常简单的 function 来处理您想要的调整,然后按组应用该 function。 这将比旋转快得多。
f <- function(i,v) {
if(all(is.na(v[grepl("^(o|d)",i)]))) v[i=="domestic_revenue"]=v[i=="total_revenue"]
return(v)
}
使用 data.table(会很快)
setDT(df)[,value:=f(indicator,value), by=.(comp_name, year)]
使用 dplyr(会更慢,但仍然比旋转更快)
df %>%
group_by(comp_name,year) %>%
mutate(value=f(indicator,value))
Output:
comp_name year indicator value
<char> <char> <char> <num>
1: A 2016 total_revenue 100
2: A 2016 overseas_revenue NA
3: A 2016 domestic_revenue 100
4: A 2017 total_revenue 100
5: A 2017 overseas_revenue 20
6: A 2017 domestic_revenue 80
7: B 2016 total_revenue 90
8: B 2016 overseas_revenue NA
9: B 2016 domestic_revenue 60
10: B 2017 total_revenue 90
11: B 2017 overseas_revenue NA
12: B 2017 domestic_revenue 90
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.