估计面板中​​随时间推移的公共集合成员的百分比

Estimating the percentage of common set members over time in a panel

我有一个时间序列面板数据集,其结构如下:有 2 只基金在每个时间段各自拥有不同的股票。

df <- data.frame(
  fund_id = c(1,1,1,1,1,1,1,1, 1, 2,2,2,2),
  time_Q = c(1,1,1,2,2,2,2,3, 3, 1,1,2,2),
  stock_id = c("A", "B", "C", "A", "C", "D", "E", "D", "E", "A", "B", "B", "C")

)

> df
   fund_id time_Q stock_id
1        1      1        A
2        1      1        B
3        1      1        C
4        1      2        A
5        1      2        C
6        1      2        D
7        1      2        E
8        1      3        D
9        1      3        E
10       2      1        A
11       2      1        B
12       2      2        B
13       2      2        C

对于每个基金,我想计算当前 time_Q 持有的股票在前一到两个季度持有的百分比。所以基本上对于每个基金和每个 time_Q,我想有 2 列过去 1 time_Q,过去 2 time_Q 显示当时持有的股票百分比也存在于每一个过去的 time_Q 年代。 结果应该是这样的:

result <- data.frame(
  fund_id = c(1,1,1,2,2),
  time_Q = c(1,2,3,1,2),
  past_1Q = c("NA",0.5,1,"NA",0.5),
  past_2Q = c("NA","NA",0,"NA","NA")
)

>  result
  fund_id time_Q past_1Q past_2Q
1       1      1      NA      NA
2       1      2     0.5      NA
3       1      3       1       0
4       2      1      NA      NA
5       2      2     0.5      NA

我目前正在考虑使用 setdiff 或 intersect 函数,但我不确定如何在面板数据集中设置格式。我正在寻找一个可扩展的 dplyr 或 data.table 解决方案,它能够涵盖多个基金、股票和时间段,并且还可以研究多达 12 个滞后时间段中的共同元素。我将不胜感激任何帮助,因为我已经在这个问题上停留了很长一段时间。

我们可以使用 dplyrpurrr 以编程方式建立一个滞后的所有权变量,然后 summarize() 使用 across() 跨越所有这些变量。首先,我们只需要一个所有权虚拟变量,并按基金和股票对数据进行分组。

library(dplyr)
library(purrr)

df_grouped <- df %>%
  mutate(owned = TRUE) %>%
  group_by(fund_id, stock_id) 

然后我们可以生成每个股票的滞后所有权,基于time_Q,将它们全部连接在一起,并且对于每个基金和time_Q,计算所有权比例。

map(
  1:2,
  ~df_grouped %>%
    mutate(
      "past_{.x}Q" := lag(owned, n = .x, order_by = time_Q)
    )
) %>%
  reduce(left_join, by = c("fund_id", "stock_id", "time_Q", "owned")) %>%
  group_by(fund_id, time_Q) %>%
  summarize(
    across(
      starts_with("past"),
      ~if (all(is.na(.x))) NA else sum(.x, na.rm = T) / n()
    )
  )
#> # A tibble: 5 × 4
#>   fund_id time_Q past_1Q past_2Q
#>     <dbl>  <dbl>   <dbl> <lgl>  
#> 1       1      1    NA   NA     
#> 2       1      2     0.5 NA     
#> 3       1      3     1   NA     
#> 4       2      1    NA   NA     
#> 5       2      2     0.5 NA

这是一个 dplyr-only 解决方案:

library(dplyr)

df %>% 
  group_by(fund_id, time_Q) %>% 
  summarise(new = list(stock_id)) %>% 
  mutate(past_1Q = lag(new, 1),
         past_2Q = lag(new, 2)) %>% 
  rowwise() %>% 
  transmute(time_Q, 
            across(past_1Q:past_2Q, ~ length(intersect(new, .x)) / length(new)))

输出

  fund_id time_Q past_1Q past_2Q
    <dbl>  <dbl>   <dbl>   <dbl>
1       1      1     0         0
2       1      2     0.5       0
3       1      3     1         0
4       2      1     0         0
5       2      2     0.5       0