根据标准 (R) 生成滚动计数

Generating a rolling tally based on criterion (R)

问题描述

我正在处理美国冲突事件的电子表格。每行代表一个事件并包含地理和时间信息。冲突事件往往发生在 'waves'(相对紧密的时间分组)中。我已经为每一波生成了一个身份变量,并想创建一个变量来衡量这些冲突事件在每一波过程中的地理分布。

wanted to do this in Excel,但不幸的是我没有可用的动态数组公式。在升级到新版本之前Excel,我想看看在R中是否可以。数据已经按地区、日期和波次排序了。

数据说明

数据集结构如下:

Country     Region     Date       Event     Wave
-------     -------    ------     -------   ------
USA         Vermont    5/1/2017   Strike    Wave 1
USA         Vermont    5/2/2017   Strike    Wave 1
USA         New Hamp.  5/3/2017   Strike    Wave 1
USA         Vermont    5/3/2017   Strike    Wave 1
USA         Maine      5/4/2017   Strike    Wave 1
USA         Washingt.  8/16/2018  Riot      Wave 2
USA         Washingt.  8/18/2018  Riot      Wave 2
USA         Oregon     8/18/2018  Protest   Wave 2
USA         Californ.  8/19/2018  Riot      Wave 2
USA         Nevada     8/20/2018  Protest   Wave 2
USA         Idaho      8/20/2018  Riot      Wave 2

我想创造什么

我想创建一个变量 ("geo_disp") 来记录在给定的 wave[=38] 中发生冲突的 region 的数量=].整个浪潮中,我希望区域数量会增加,我希望geo_disp变量记录这一点。

你会注意到,当两个事件发生在同一天但发生在不同的地点时,两者都会记录在地区总数中。

这是我想要的数据:

Country     Region     Date       Event     Wave    geo_disp
-------     -------    ------     -------   ------  --------
USA         Vermont    5/1/2017   Strike    Wave 1   1
USA         Vermont    5/2/2017   Strike    Wave 1   1
USA         New Hamp.  5/3/2017   Strike    Wave 1   2
USA         Vermont    5/3/2017   Strike    Wave 1   2
USA         Maine      5/4/2017   Strike    Wave 1   3
USA         Washingt.  8/16/2018  Riot      Wave 2   1
USA         Washingt.  8/18/2018  Riot      Wave 2   2
USA         Oregon     8/18/2018  Protest   Wave 2   2
USA         Californ.  8/19/2018  Riot      Wave 2   3
USA         Nevada     8/20/2018  Protest   Wave 2   5
USA         Idaho      8/20/2018  Riot      Wave 2   5

如何使用 R 创建 geo_disp 变量?

提前致谢 - 非常感谢。

如果您不介意删除同一 wave 中的重复区域,您可以使用 tidyverse 尝试这种方法:

library(tidyverse)

df <- tribble(
  ~Country,   ~Region,     ~Date,       ~Event,     ~Wave,
  'USA',         'Vermont',    '5/1/2017',   'Strike',    'Wave 1',
  'USA',         'Vermont',    '5/2/2017',   'Strike',    'Wave 1',
  'USA',         'New Hamp.',  '5/3/2017',   'Strike',    'Wave 1',
  'USA',         'Vermont',    '5/3/2017',   'Strike',    'Wave 1',
  'USA',         'Maine',      '5/4/2017',   'Strike',    'Wave 1',
  'USA',         'Washingt.',  '8/16/2018',  'Riot',      'Wave 2',
  'USA',         'Washingt.',  '8/18/2018',  'Riot',      'Wave 2',
  'USA',         'Oregon',     '8/18/2018',  'Protest',   'Wave 2',
  'USA',         'Californ.',  '8/19/2018',  'Riot',      'Wave 2',
  'USA',         'Nevada',     '8/20/2018',  'Protest',   'Wave 2',
  'USA',        'Idaho',      '8/20/2018',  'Riot',      'Wave 2'
)

df %>% distinct(Region, .keep_all = T) %>% group_by(Wave) %>% mutate(geo_disp = 1:n())

请注意,dput() 是使数据易于在 R 中共享的好方法。

> dput(df)
structure(list(Country = c("USA", "USA", "USA", "USA", "USA", 
"USA", "USA", "USA", "USA", "USA", "USA"), Region = c("Vermont", 
"Vermont", "New Hamp.", "Vermont", "Maine", "Washingt.", "Washingt.", 
"Oregon", "Californ.", "Nevada", "Idaho"), Date = c("5/1/2017", 
"5/2/2017", "5/3/2017", "5/3/2017", "5/4/2017", "8/16/2018", 
"8/18/2018", "8/18/2018", "8/19/2018", "8/20/2018", "8/20/2018"
), Event = c("Strike", "Strike", "Strike", "Strike", "Strike", 
"Riot", "Riot", "Protest", "Riot", "Protest", "Riot"), Wave = c("Wave 1", 
"Wave 1", "Wave 1", "Wave 1", "Wave 1", "Wave 2", "Wave 2", "Wave 2", 
"Wave 2", "Wave 2", "Wave 2")), row.names = c(NA, -11L), class = c("tbl_df", 
"tbl", "data.frame"))

保留整个数据集的 dplyr 解决方案。

library(dplyr)

df %>% group_by(Wave) %>% mutate(disp_geo = cumsum(!duplicated(Region)))
#> # A tibble: 11 x 6
#> # Groups:   Wave [2]
#>    Country Region    Date      Event   Wave   disp_geo
#>    <chr>   <chr>     <chr>     <chr>   <chr>     <int>
#>  1 USA     Vermont   5/1/2017  Strike  Wave 1        1
#>  2 USA     Vermont   5/2/2017  Strike  Wave 1        1
#>  3 USA     New Hamp. 5/3/2017  Strike  Wave 1        2
#>  4 USA     Vermont   5/3/2017  Strike  Wave 1        2
#>  5 USA     Maine     5/4/2017  Strike  Wave 1        3
#>  6 USA     Washingt. 8/16/2018 Riot    Wave 2        1
#>  7 USA     Washingt. 8/18/2018 Riot    Wave 2        1
#>  8 USA     Oregon    8/18/2018 Protest Wave 2        2
#>  9 USA     Californ. 8/19/2018 Riot    Wave 2        3
#> 10 USA     Nevada    8/20/2018 Protest Wave 2        4
#> 11 USA     Idaho     8/20/2018 Riot    Wave 2        5

按'Wave'分组后我们可以使用match

library(data.table)
setDT(df)[, geo_disp := match(Region, unique(Region)), Wave]

或与dplyr

library(dplyr)
df %>%
  group_by(Wave) %>%
  mutate(geo_disp = match(Region, unique(Region))

以前的答案解决了这个问题,但要将其添加到累积计数(我认为 Yasha 正在努力实现)你会做:

library(data.table)
set.seed(1)
toy_data = data.table(
  region = sample(LETTERS[1:3], 10, replace = T),
  wave = c(rep(1,5),rep(2,5))
)
toy_data[,count:=cummax(match(region, unique(region))), wave]
# > toy_data
#     region wave count
#  1:      A    1     1
#  2:      C    1     2
#  3:      A    1     2
#  4:      B    1     3
#  5:      A    1     3
#  6:      C    2     1
#  7:      C    2     1
#  8:      B    2     2
#  9:      B    2     2
# 10:      C    2     2