在dplyr中按两个变量分组并选择其中一个的最高值

时间:2018-11-07 10:03:58

标签: r dplyr grouping

我在一些州拥有多年的选举数据,每年的候选人数量都在变化。下面是一个近似的代表。

library(tidyverse)

set.seed(1124)

df <- cbind(
  sample(LETTERS[1:3], size = 40, replace = TRUE),
  as.numeric(sample(2009:2013, size = 40, replace = TRUE)), 
  sample(letters, size = 40, replace = TRUE),
  as.numeric(sample(1:5000, size = 40))
)

colnames(df) <- c("states", "year", "candidate", "votes")

df <- as.tibble(df)

df
#> # A tibble: 40 x 4
#>    states year  candidate votes
#>    <chr>  <chr> <chr>     <chr>
#>  1 B      2010  w         1402 
#>  2 A      2012  o         3646 
#>  3 A      2009  x         4073 
#>  4 A      2012  w         713  
#>  5 A      2012  n         4810 
#>  6 C      2011  i         4096 
#>  7 B      2010  u         215  
#>  8 A      2012  j         1928 
#>  9 C      2013  e         1889 
#> 10 B      2013  z         4888 
#> # ... with 30 more rows

我只想在每个州的最后 n 年选举中将行存储在单独的df中。例如,最后两个可能是:A 2012,A 2010,B 2013,B 2010,C 2012,C 2009及其所有相关的候选人和投票信息(以及我没有在不必要的时候加入代表的其他信息) )。

我以为我可以用下面的代码来实现,但是我正在选择所有内容……group_by(states)top_n(2, wt = year)也不产生预期的结果。

我看不到其他任何方式。其他解决方案,例如this one不太适合。

select_df <- df %>% 
  group_by(states, year) %>% 
  top_n(n = 2, wt = year)

我将非常感谢任何指针!

2 个答案:

答案 0 :(得分:1)

您可以执行以下操作以避免与top_n的联系有关的问题:

df %>% 
  arrange(states, year) %>%  # For clearer ordering
  group_by(states, year) %>%  
  nest() %>%                 # nest everything which is not state or year  
  group_by(states) %>%       # We want to have top years by states
  top_n(n = 2, year) %>%     # No ties and no problems with top_n
  unnest()                   # Duplicated rows for several candidates per state and year

# A tibble: 16 x 4
# Groups:   states [3]
   states year  candidate votes
   <chr>  <chr> <chr>     <chr>
 1 A      2012  o         3646 
 2 A      2012  w         713  
 3 A      2012  n         4810 
 4 A      2012  j         1928 
 5 A      2012  h         1699 
 6 A      2013  c         2873 
 7 B      2012  n         3502 
 8 B      2012  z         1079 
 9 B      2012  k         3207 
10 B      2013  z         4888 
11 B      2013  l         3483 
12 C      2012  x         2241 
13 C      2012  b         4994 
14 C      2013  e         1889 
15 C      2013  h         3858 
16 C      2013  z         186  

没有嵌套(如果使用太大的数据集可能会很麻烦),您首先要提取每个州的前几年,然后按如下所示对其进行过滤:

df %>% 
  arrange(states, year) %>%   # Sorting is important to select correct years
  group_by(states) %>% 
  mutate(top_year = list(tail(unique(year), 2))) %>%  # If not pre sorted, use sort() here
  rowwise() %>% 
  filter(year %in% top_year)

第一个解决方案的说明
为什么我们必须使用nest()?让我们看一下,如果我们忽略它会发生什么:

df %>% 
  arrange(states, year) %>%  
  group_by(states, year) %>% 
  group_by(states) %>%       
  top_n(n = 2, year)         

# A tibble: 11 x 4
# Groups:   states [3]
#    states year  candidate votes
#    <chr>  <chr> <chr>     <chr>
#  1 A      2012  o         3646 
#  2 A      2012  w         713  
#  3 A      2012  n         4810 
#  4 A      2012  j         1928 
#  5 A      2012  h         1699 
#  6 A      2013  c         2873 
#  7 B      2013  z         4888 
#  8 B      2013  l         3483 
#  9 C      2013  e         1889 
# 10 C      2013  h         3858 
# 11 C      2013  z         186  

对于状态A而言,它没有什么区别,但是对于状态B和C而言,这没有什么区别。这是由于top_n的工作方式。它将选择前2行,并按可变年份加权。 对于状态A,这是2013年,然后是2012年。状态A和2012年有几行,因此top_n选择所有这些行。对于州B和C,最高年份(2013)已经填充了2行或更多行,因此top_n选择并完成。因此,它会选择年份最高的行,并选择年份,直到行数被填满为止。

让我们看看如果我们嵌套数据会发生什么:

df %>% 
  arrange(states, year) %>%  
  group_by(states, year) %>%  
  nest() 

# A tibble: 14 x 3
#    states year  data            
#    <chr>  <chr> <list>          
#  1 A      2009  <tibble [3 x 2]>
#  2 A      2011  <tibble [2 x 2]>
#  3 A      2012  <tibble [5 x 2]>
#  4 A      2013  <tibble [1 x 2]>
#  5 B      2009  <tibble [2 x 2]>
#  6 B      2010  <tibble [7 x 2]>
#  7 B      2011  <tibble [1 x 2]>
#  8 B      2012  <tibble [3 x 2]>
#  9 B      2013  <tibble [2 x 2]>
# 10 C      2009  <tibble [3 x 2]>
# 11 C      2010  <tibble [2 x 2]>
# 12 C      2011  <tibble [4 x 2]>
# 13 C      2012  <tibble [2 x 2]>
# 14 C      2013  <tibble [3 x 2]>

现在我们每年没有多行,因此我们确实用top_n选择了前2年。

答案 1 :(得分:0)

建议尝试slice

df %>% 
  mutate(year = as.numeric(year)) %>%
  arrange(-desc(states), -desc(year)) %>%
  group_by(states) %>%
  mutate(id = row_number()) %>%
  slice((n()-1):n())

enter image description here