名师讲堂|使用 R 语言计算 Shapley-Shubik 权力指数:以上市公司前 10 大股东份额数据为例

Shapley-Shubik 指数是一种衡量投票权力的指标,它基于博弈论中的 Shapley 值的概念。Shapley-Shubik 指数可以用来分析在一个决策过程中,每个参与者对最终决策的贡献程度。

具体来说,Shapley-Shubik 指数反映了一个参与者在一个决策过程中成为“关键”参与者的概率。所谓“关键”参与者,是指如果该参与者不参与,原本可以通过的决议就无法通过。

Shapley-Shubik 指数的计算步骤如下:

  1. 列出所有可能的参与者排列组合。
  2. 对于每一种排列组合,计算该参与者是否为“关键”参与者。
  3. 统计每个参与者成为“关键”参与者的次数。
  4. 将每个参与者成为“关键”参与者的次数除以所有排列组合的总数,得到该参与者的 Shapley-Shubik 指数。

Shapley-Shubik 指数的取值范围是 [0, 1]。指数越大,表示该参与者在决策过程中的影响力越大。

在上市公司相关的研究中,Shapley-Shubik 指数可以用来衡量各股东的权力大小。本次课程中我们将以上市公司前 10 大股东份额数据为例,讲解如何在 Stata 中计算 Shapley-Shubik 指数。

一个简单的例子

考虑有四个团体,分别占据 40,39,11 和 11 个席位。总共是 101 个席位,决议通过的规则是 >= 51 票。计算每个团体的 Shapley-Shubik 权力指数。

一个简单的方法是借助这个在线应用:https://homepages.warwick.ac.uk/~ecaae/ssdirect.html

计算结果:

从 Shapley-Shubik 指数的计算过程中可以看到,如果增加一个团体,计算过程的耗时会增加 1 倍。

在 R 语言中可以使用 GameTheory 包的 ShapleyShubik() 函数计算 Shapley-Shubik 指数:

library(tidyverse)
library(GameTheory)

seats <- c(40, 39, 11, 11)
names <- c("A", "B", "C", "D")
SSI <- ShapleyShubik(51, seats, names)
summary(SSI)
#>
#> Distribution of the agents
#>
#> A B C D
#> 40 39 11 11
#>
#> Minimum amount of votes to pass a vote: 51
#>
#> Shapley-Shubik Power Index
#>
#> A B C D
#> 0.5000000 0.1666667 0.1666667 0.1666667

我们也可以自己编程实现这一过程:

y <- c(40, 39, 11, 11)
quota <- 51
n <- length(y)
res1 <- permutations(n, n)
res1
#>       [,1] [,2] [,3] [,4]
#> [1,] 1 2 3 4
#> [2,] 1 2 4 3
#> [3,] 1 3 2 4
#> [4,] 1 3 4 2
#> [5,] 1 4 2 3
#> [6,] 1 4 3 2
#> [7,] 2 1 3 4
#> [8,] 2 1 4 3
#> [9,] 2 3 1 4
#> [10,] 2 3 4 1
#> [11,] 2 4 1 3
#> [12,] 2 4 3 1
#> [13,] 3 1 2 4
#> [14,] 3 1 4 2
#> [15,] 3 2 1 4
#> [16,] 3 2 4 1
#> [17,] 3 4 1 2
#> [18,] 3 4 2 1
#> [19,] 4 1 2 3
#> [20,] 4 1 3 2
#> [21,] 4 2 1 3
#> [22,] 4 2 3 1
#> [23,] 4 3 1 2
#> [24,] 4 3 2 1
res2 <- apply(res1, 1, function(x) {
x[sum(cumsum(y[x]) < quota) + 1]
})

res2
#>  [1] 2 2 3 3 4 4 1 1 1 4 1 3 1 1 1 4 1 2 1 1 1 3 1 2
Power <- matrix(NA, ncol = 1, nrow = n)
for (i in 1:n) {
Power[i, 1] <- sum(res2 == i)
}
Power
#>      [,1]
#> [1,] 12
#> [2,] 4
#> [3,] 4
#> [4,] 4
Power/factorial(n)
#>           [,1]
#> [1,] 0.5000000
#> [2,] 0.1666667
#> [3,] 0.1666667
#> [4,] 0.1666667

计算上市公司前 5 大股东的权力指数

为了节约时间,这里我只计算了前 5 大股东的。data.dta 中存储了一些上市公司的前 10 大股东份额数据:

haven::read_dta("data.dta") -> df
df
#> # A tibble: 100 × 12
#> stkcd year top1 top2 top3 top4 top5 top6 top7
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 600592 2013 0.379 0.0732 0.0600 0.0275 0.0250 0.0188 0.00740
#> 2 600692 2010 0.325 0.00960 0.00360 0.00340 0.00300 0.00270 0.00260
#> 3 603315 2018 0.577 0.0486 0.0444 0.0320 0.0188 0.0185 0.0185
#> 4 600580 2016 0.475 0.0592 0.0173 0.0173 0.0160 0.0142 0.0104
#> 5 600213 2020 0.510 0.00920 0.00840 0.00710 0.00590 0.00450 0.00450
#> 6 404 2011 0.299 0.0645 0.0396 0.0262 0.0208 0.0118 0.00930
#> 7 2559 2013 0.382 0.0590 0.0231 NA NA NA NA
#> 8 895 2009 0.515 0.0397 0.0342 0.0206 0.0190 0.0169 0.0157
#> 9 300100 2012 0.642 0.0200 0.0112 0.00730 0.00510 0.00480 0.00460
#> 10 2120 2015 0.441 0.0349 0.0313 0.0134 0.0128 0.0117 0.00510
#> # ℹ 90 more rows
#> # ℹ 3 more variables: top8 <dbl>, top9 <dbl>, top10 <dbl>

删除前 5 大股东份额小于 50% 的:

df %>%
select(stkcd, year, paste0("top", 1:5)) %>%
rowwise() %>%
mutate(total = sum(c_across(contains("top")), na.rm = T)) %>%
ungroup() %>%
filter(total >= 0.5) %>%
mutate_at(vars(contains("top")), ~if_else(is.na(.x), 0, .x)) -> dfnew

dfnew
#> # A tibble: 72 × 8
#> stkcd year top1 top2 top3 top4 top5 total
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 600592 2013 0.379 0.0732 0.0600 0.0275 0.0250 0.564
#> 2 603315 2018 0.577 0.0486 0.0444 0.0320 0.0188 0.721
#> 3 600580 2016 0.475 0.0592 0.0173 0.0173 0.0160 0.584
#> 4 600213 2020 0.510 0.00920 0.00840 0.00710 0.00590 0.541
#> 5 895 2009 0.515 0.0397 0.0342 0.0206 0.0190 0.628
#> 6 300100 2012 0.642 0.0200 0.0112 0.00730 0.00510 0.685
#> 7 2120 2015 0.441 0.0349 0.0313 0.0134 0.0128 0.533
#> 8 688056 2020 0.368 0.241 0.0821 0.0553 0.00890 0.755
#> 9 2281 2015 0.454 0.0661 0.0192 0.0122 0.00960 0.561
#> 10 600481 2014 0.512 0.0119 0.00620 0.00590 0.00460 0.541
#> # ℹ 62 more rows

然后就可以计算了:

dfnew %>%
select(-total) %>%
nest(data = -c("stkcd", "year")) %>%
mutate(res = map(data, function(x){
ShapleyShubik(0.5, unlist(x)) %>%
summary() %>%
as_tibble() %>%
mutate(var = paste0("Power", 1:5))
})) -> dfb
dfb %>%
unnest(data) %>%
unnest(res) %>%
spread(var, value)
#> # A tibble: 72 × 12
#> stkcd year top1 top2 top3 top4 top5 Power1 Power2 Power3
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 600592 2013 0.379 0.0732 0.0600 0.0275 0.0250 0.383 0.383 0.133
#> 2 603315 2018 0.577 0.0486 0.0444 0.0320 0.0188 1 0 0
#> 3 600580 2016 0.475 0.0592 0.0173 0.0173 0.0160 0.65 0.15 0.0667
#> 4 600213 2020 0.510 0.00920 0.00840 0.00710 0.00590 1 0 0
#> 5 895 2009 0.515 0.0397 0.0342 0.0206 0.0190 1 0 0
#> 6 300100 2012 0.642 0.0200 0.0112 0.00730 0.00510 1 0 0
#> 7 2120 2015 0.441 0.0349 0.0313 0.0134 0.0128 0.383 0.383 0.133
#> 8 688056 2020 0.368 0.241 0.0821 0.0553 0.00890 0.583 0.25 0.0833
#> 9 2281 2015 0.454 0.0661 0.0192 0.0122 0.00960 0.5 0.5 0
#> 10 600481 2014 0.512 0.0119 0.00620 0.00590 0.00460 1 0 0
#> # ℹ 62 more rows
#> # ℹ 2 more variables: Power4 <dbl>, Power5 <dbl>

点击这里跳转到 RStata 短书平台获取附件:名师讲堂|使用 R 语言计算 Shapley-Shubik 权力指数:以上市公司前 10 大股东份额数据为例

评论