问题描述
我有一个名称和年份的数据框,其中包含一个虚拟变量,用于确定名称是否出现在一年中。
我正在尝试创建一个数据框来告诉我
-
- 当年出现的名字总数,以及
-
- 当年出现但前一年未出现的人数。
在下面的示例中,2017 年只有一个人 (Terry) 发生,而前一年没有发生,因此总数和新人均为 1。2018 年发生了三个人,但只有两个人是新人,因为 Terry 发生在前一年。如果某人出现在 2017 年和 2019 年但未出现在 2018 年,则应将其归类为 2019 年的新人。
示例
Name x2017 x2018 x2019
1 Terry 1 1 0
2 Sam 0 0 1
3 Nic 0 1 1
4 Sarah 0 1 1
data.frame(
Name = c("Terry","Sam","Nic","Sarah"),x2017 = c(1,0),x2018 = c(1,1,1),x2019 = c(0,1)
)
我正在尝试创建的输出
Year Total New
1 2017 1 1
2 2018 3 2
3 2019 3 1
我尝试过过滤和使用行总和,但我觉得有一个我不知道的函数可以做到这一点。
谢谢!
解决方法
mutate(new = as.numeric(values == 1 & lag(values) == 0),new = ifelse(is.na(new),values,new)) %>%
部分来自 stefan
(感谢他,谢谢 stefan)。
区别在于parse_number
library(tidyverse)
df %>%
pivot_longer(
cols = -Name,names_to = "Year",values_to = "values"
) %>%
mutate(Year = parse_number(Year)) %>%
mutate(new = as.numeric(values == 1 & lag(values) == 0),new)) %>%
group_by(Year) %>%
summarise(Total = sum(values),New = sum(new))
输出:
Year Total New
* <dbl> <dbl> <dbl>
1 2017 1 1
2 2018 3 2
3 2019 3 1
,
更新-02 我很抱歉,因为我不得不修改我的解决方案,因为我意识到只有在前一年出现的名称才不会被视为新名称,因此您也可以将其用于示例数据和页面下方显示的数据:
library(dplyr)
library(purrr)
df %>%
summarise(across(2:4,~ sum(.x))) %>%
bind_cols() %>%
pivot_longer(everything(),values_to = "Total",names_prefix = "x") %>%
left_join(df %>% select(2:4) %>% pmap_dfr(~ {x <- c(...); x - lag(x,default = 0)}) %>%
summarise(across(everything(),~ sum(.x == 1))) %>%
pivot_longer(everything(),values_to = "New",names_prefix = "x"),by = "Year")
# A tibble: 3 x 3
Year Total New
<chr> <dbl> <dbl>
1 2017 1 1
2 2018 3 2
3 2019 3 1
,
也许这就是您要找的:
- 使用例如重塑为长格式
tidy::pivot_longer
- 按
Name
分组并利用dplyr::lag
添加一个人是否是新人的指示 - 按年份总结
d <- data.frame(
Name = c("Terry","Sam","Nic","Sarah"),x2017 = c(1,0),x2018 = c(1,1,1),x2019 = c(0,1)
)
library(dplyr)
library(tidyr)
d %>%
tidyr::pivot_longer(-Name,names_to = "year") %>%
mutate(year = gsub("^x","",year)) %>%
group_by(Name) %>%
mutate(new = as.numeric(value == 1 & lag(value) == 0),value,new)) %>%
ungroup() %>%
group_by(year) %>%
summarise(total = sum(value),new = sum(new))
#> # A tibble: 3 x 3
#> year total new
#> <chr> <dbl> <dbl>
#> 1 2017 1 1
#> 2 2018 3 2
#> 3 2019 3 1
,
case-I 当只需要在前一行检查记录时。
df %>%
pivot_longer(!Name,names_to = 'Year',names_prefix = 'x') %>%
group_by(Year) %>%
summarise(total = sum(value),new = list(Name[value == 1]),.groups = 'drop') %>%
mutate(new = map2_int(new,lag(new),~ sum(!(.x %in% .y))))
# A tibble: 3 x 3
Year total new
<chr> <dbl> <int>
1 2017 1 1
2 2018 3 2
3 2019 3 1
当必须查看所有先前行的记录时的案例 II。同时使用 map_*
和 accumulate
。采用的策略-
-
pivot_longer
首先。使用x
参数 直接从年份中删除 -
group_by
当年 - 在
n()
中计算该年份的总值list
和名称 - 使用
new
变异map2_int
,第一个参数仅作为该列表,第二个参数作为accumulate
d 和lag
ged list 。 -
map2_int
因此计算出该行中TRUE
的总数。
names_prefix
library(tidyverse)
df %>%
pivot_longer(!Name,lag(accumulate(new,union,.init = first(new))[-1]),~ sum(!(.x %in% .y))))
#> # A tibble: 3 x 3
#> Year total new
#> <chr> <int> <int>
#> 1 2017 1 1
#> 2 2018 3 2
#> 3 2019 3 1