r-基于顺序行值创建新的数据帧



我有一个由名称和年份组成的数据帧,其中有一个用于判断名称是否发生在一年中的伪变量。

我正试图创建一个数据帧,告诉我

    1. 当年出现的名称总数,以及
    1. 当年出现但前一年没有出现的数量

在下面的例子中,2017年只有一个人出现(Terry(,前一年没有,所以总数和新人数都是1。2018年出现了三个人,但只有两个人是新的,就像特里在前一年出现的那样。如果有人在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, 0, 0), 
x2018 = c(1, 0, 1, 1), 
x2019 = c(0, 1, 1, 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 = ifelse(is.na(new), values, 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

Updated-02我很抱歉不得不修改我的解决方案,因为我意识到只有在前一年出现了一个名称时,它才不被认为是新的,所以你也可以将其用于你的样本数据和页面下方的数据:

library(dplyr)
library(purrr)

df %>% 
summarise(across(2:4, ~ sum(.x))) %>%
bind_cols() %>% 
pivot_longer(everything(), names_to = "Year", 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(), names_to = "Year", 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

也许这就是您想要的:

  1. 使用例如tidy::pivot_longer将形状重塑为长格式
  2. Name分组,并利用dplyr::lag添加一个人是否新的指示符
  3. 按年份汇总
d <- data.frame(
Name = c("Terry", "Sam", "Nic", "Sarah"), 
x2017 = c(1, 0, 0, 0), 
x2018 = c(1, 0, 1, 1), 
x2019 = c(0, 1, 1, 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),
new = ifelse(is.na(new), 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,当必须将记录查看到以前的所有行中时。同时使用CCD_ 6和CCD_。采用的策略-

  • pivot_longer优先。使用names_prefix参数从年份中直接删除x
  • 当年group_by
  • 计算总值n()list中当年的名称
  • 使用map2_int突变new,第一个参数仅作为该列表,第二个参数作为accumulated和lagged列表
  • CCD_ 18由此计算该行中的CCD_

library(tidyverse)
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(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

最新更新