累计按R中另一个变量分组的列中的不同值的数量

时间:2016-02-02 15:19:44

标签: r dataframe dplyr

我正在努力处理来自R中的data.frame的数据请求,其中包含一个包含俱乐部的表,他们的ID,他们成立的年份,他们所属的地区的ID以及他们去过的年份关闭。 data.frame dat看起来像

club_id   founded    district_id    closed
   1       2012         1             NA
   2       2012         2            2014
   3       2013         2             NA
   4       2013         3            2014
  ...
NA列中的

closed表示该俱乐部仍然存在于当前年份(2016年)。

我想要的是每年仍然存在的俱乐部的数量,例如,这将为我提供上面的数据片段:

2012   2013   2014 ...
  2      4     2   ...

我尝试使用dplyr

dat %>%
 group_by(founded) %>%
 summarise(clubs_per_year = n_distinct(club_id))

但是,这只给了我每年新成立的俱乐部数量,而不是每年现有俱乐部的总数。

4 个答案:

答案 0 :(得分:2)

我不确定如何使用dplyr实现此目的,但这是一个可能的data.table解决方案。这基本上是为每个俱乐部创建一个序列,同时用当前年份替换NA,然后计算每年的事件数

library(data.table)
setDT(df)[, .(Year = founded:(replace(closed, is.na(closed), year(Sys.Date())) - 1L)), 
            by = club_id
          ][, .(Uniques = uniqueN(club_id)), by = Year]

#    Year Uniques
# 1: 2012       2
# 2: 2013       4
# 3: 2014       2
# 4: 2015       2

答案 1 :(得分:1)

我尝试了一个完整的解决方案。攻击计划是为每个俱乐部生成一系列活跃的年份,然后计算每个活跃年份的俱乐部ID。

首先,我们计算出每个俱乐部的最后一个活跃年份。

max_year <- 2015
years <- data_frame(
  club_id = 1:4, 
  founded = c(2012, 2012, 2013, 2013),
  closed = c(NA, 2014, NA, 2014))

years <- years %>% 
  mutate(last_active = ifelse(is.na(closed), max_year, closed - 1))
years
#> Source: local data frame [4 x 4]
#> 
#>   club_id founded closed last_active
#>     (int)   (dbl)  (dbl)       (dbl)
#> 1       1    2012     NA        2015
#> 2       2    2012   2014        2013
#> 3       3    2013     NA        2015
#> 4       4    2013   2014        2013

接下来,我们创建另一个数据框,其中包含数据中每个founded - last_active范围内每个活动年份的一行。我们使用do函数执行此操作。 do让我们计算数据帧上的任意函数;唯一的规则是函数需要返回一个数据框。 do尊重分组变量,因此也会返回分组列。

# Create a single-column data-frame with a sequence of values
seq_df <- function(col_name, min, max) {
  data.frame(seq(min, max)) %>% setNames(col_name)
}

year_scheme <- years %>% 
  # Find each found-last_active pairings
  select(founded, last_active) %>% 
  distinct %>% 
  # Create a sequence of rows for each of those pairings
  group_by(founded, last_active) %>% 
  do(seq_df("active_year", .$founded, .$last_active)) %>% 
  ungroup
year_scheme
#> Source: local data frame [10 x 3]
#> 
#>    founded last_active active_year
#>      (dbl)       (dbl)       (int)
#> 1     2012        2013        2012
#> 2     2012        2013        2013
#> 3     2012        2015        2012
#> 4     2012        2015        2013
#> 5     2012        2015        2014
#> 6     2012        2015        2015
#> 7     2013        2013        2013
#> 8     2013        2015        2013
#> 9     2013        2015        2014
#> 10    2013        2015        2015

最后,我们可以加入表并计算组ID。

full_years <- left_join(years, year_scheme)
#> Joining by: c("founded", "last_active")
full_years
#> Source: local data frame [10 x 5]
#> 
#>    club_id founded closed last_active active_year
#>      (int)   (dbl)  (dbl)       (dbl)       (int)
#> 1        1    2012     NA        2015        2012
#> 2        1    2012     NA        2015        2013
#> 3        1    2012     NA        2015        2014
#> 4        1    2012     NA        2015        2015
#> 5        2    2012   2014        2014        2012
#> 6        2    2012   2014        2014        2013
#> 7        3    2013     NA        2015        2013
#> 8        3    2013     NA        2015        2014
#> 9        3    2013     NA        2015        2015
#> 10       4    2013   2014        2014        2013

# years per club
full_years %>% count(club_id)
#> Source: local data frame [4 x 2]
#> 
#>   club_id     n
#>     (int) (int)
#> 1       1     4
#> 2       2     2
#> 3       3     3
#> 4       4     1

# clubs per year
full_years %>% count(active_year)
#> Source: local data frame [4 x 2]
#> 
#>   active_year     n
#>         (int) (int)
#> 1        2012     2
#> 2        2013     4
#> 3        2014     2
#> 4        2015     2

答案 2 :(得分:0)

此解决方案使用dcast包中的data.table

library(data.table)

##Example data
DT <- data.table(club_id=1:4, founded=rep(2012:2013, each=2),
                 district_id=c(1, 2, 2, 3), closed=rep(c(NA, 2014), 2))

## Fill in NAs with current year, create row for each year the club
##  exists, cast to columns for each year, and get the count of clubs
##  per year using length function
dcast(DT[, .(year=founded:ifelse(is.na(closed), year(Sys.Date()), closed)),
      by=club_id],  . ~ year, length, fill=0)

##    . 2012 2013 2014 2015 2016
## 1: .    2    4    4    2    2

以下版本类似,但除非全年开放,否则不会计算一年内的俱乐部。请注意俱乐部在同一年开放和关闭的情况。我已经添加了一个在2015年开放和关闭的俱乐部。

DT2 <- data.table(club_id=1:5, founded=c(rep(2012:2013, each=2), 2015),
                  district_id=c(1, 2, 2, 3, 3),
                  closed=c(rep(c(NA, 2014), 2), 2015))

## Fill in missing values with the current year
DT2[, closed2:=ifelse(is.na(closed), year(Sys.Date()), closed)]

## Cast to columns as before, ignore cases where the club's open and
##  closed years match, and then subtract one from the closed year
dcast(DT2[founded!=closed2, .(year=founded:(closed2-1)), by=club_id],
      . ~ year, length, fill=0)

##    . 2012 2013 2014 2015
## 1: .    2    4    2    2

答案 3 :(得分:0)

以下是具有不同方法的dplyr解决方案

注意:我在几天前想出了这个,但我发现了n_distinct的错误并报告了它;它现在已在最新的开发版本中修复。在dplyr的旧版本中,我必须使用dplyr::n_distinct,但当前版本只需要n_distinct

此方法会创建一个带有年份列的data.frame,并根据dat data.frame(来自OP的数据)对其进行修改

library(dplyr)

yrdf <- data.frame(year = 2012:2015) # "dat" could be used to create this as well.
## For each year calculate the count based on the data in 'dat'
yrdf %>%
    group_by(year) %>%
    mutate(count = n_distinct(
                       dat$club_id[ (is.na(dat$closed) | (dat$closed > year)) & dat$founded <= year]
                       )
    ) %>%
    ungroup

##    year count
##   (int) (int)
## 1  2012     2
## 2  2013     4
## 3  2014     2
## 4  2015     2