Shapley-Shubik 指数是一种衡量投票权力的指标,它基于博弈论中的 Shapley 值的概念。Shapley-Shubik 指数可以用来分析在一个决策过程中,每个参与者对最终决策的贡献程度。
具体来说,Shapley-Shubik 指数反映了一个参与者在一个决策过程中成为“关键”参与者的概率。所谓“关键”参与者,是指如果该参与者不参与,原本可以通过的决议就无法通过。
Shapley-Shubik 指数的计算步骤如下:
- 列出所有可能的参与者排列组合。
- 对于每一种排列组合,计算该参与者是否为“关键”参与者。
- 统计每个参与者成为“关键”参与者的次数。
- 将每个参与者成为“关键”参与者的次数除以所有排列组合的总数,得到该参与者的 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 倍,所以我们还是使用 Mata 来提升计算速度。
mata: y = (40 \ 39 \ 11 \ 11) quota = 51 levels = colshape((1..rows(y)), 1) n = factorial(rows(levels)) info = cvpermutesetup(levels, unique = 1) i = 0 P = J(n, rows(levels), .) while ((levels = cvpermute(info)) != J(0, 1, .)) { ++i P[i,] = levels' } P
y[P[10,]]
// 循环所有的组合 R = J(n, 1, .) for (i = 1; i <= n; i ++) { R[i, 1] = P[i, colsum(runningsum(y[P[i,]]) :< quota) + 1] } R
Power = J(rows(y), 1, .) for (i = 1; i <= rows(y); i ++) { Power[i, 1] = colsum(R :== i) }
Power :/ factorial(4) end
|
cvpermute() 是用来获取所有的排列的,使用方法是这样的:
mata: levels = (1 \ 2 \ 3 \ 4) info = cvpermutesetup(levels, unique = 1) cvpermute(info) cvpermute(info) cvpermute(info) end
|
可以看到每次 cvpermute(info) 都会得到不同的排列,所以上面的代码就是把不同的排列组合成了一个 24 行的矩阵。
runningsum() 函数是用来计算矩阵的累加的:
mata: runningsum(1 \ 2 \ 3)
*> 1 *> +-----+ *> 1 | 1 | *> 2 | 3 | *> 3 | 6 | *> +-----+
|
然后我们就可以编写一个函数封装这个过程了:
mata: real colvector ShapleyShubik(real colvector y, real scalar quota) { levels = colshape((1..rows(y)), 1) n = factorial(rows(levels)) info = cvpermutesetup(levels, unique = 1) i = 0 P = J(n, rows(levels), .) while ((levels = cvpermute(info)) != J(0, 1, .)) { ++i P[i,] = levels' } R = J(n, 1, .) for (i = 1; i <= n; i ++) { R[i, 1] = P[i, colsum(runningsum(y[P[i,]]) :< quota) + 1] }
Power = J(rows(y), 1, .) for (i = 1; i <= rows(y); i ++) { Power[i, 1] = colsum(R :== i) }
return(Power :/ n) } y = (40 \ 39 \ 11 \ 11) ShapleyShubik(y, 51) end
*> 1 *> +---------------+ *> 1 | .5 | *> 2 | .1666666667 | *> 3 | .1666666667 | *> 4 | .1666666667 | *> +---------------+
|
计算上市公司前 5 大股东的权力指数
为了节约时间,这里我只计算了前 5 大股东的。data.dta 中存储了一些上市公司的前 10 大股东份额数据:
use data.dta, clear
drop top6-top10
egen total = rowtotal(top*) drop if total < 0.5 drop total
forval i = 1/5 { replace top`i' = 0 if mi(top`i') }
forval i = 1/5 { gen Power`i' = . }
mata: stock_mat = st_data(., 3..7) Power_mat = J(rows(stock_mat), cols(stock_mat), .)
for (j = 1; j <= rows(stock_mat); j++) { j tempmat = stock_mat[j,] res_mat = ShapleyShubik(colshape(tempmat, 1), 0.5) Power_mat[j,] = rowshape(res_mat, 1) } Power_mat
st_store(., 8..12, Power_mat) end
save 计算结果, replace
|

编译 Mata 程序
由于 Mata 是编译型语言,所以我们也可以把 Mata 程序编译好再使用:
首先把下面的代码存储到 ShapleyShubik.mata 文件里面:
mata: real colvector ShapleyShubik(real colvector y, real scalar quota) { levels = colshape((1..rows(y)), 1) n = factorial(rows(levels)) info = cvpermutesetup(levels, unique = 1) i = 0 P = J(n, rows(levels), .) while ((levels = cvpermute(info)) != J(0, 1, .)) { ++i P[i,] = levels' } R = J(n, 1, .) for (i = 1; i <= n; i ++) { R[i, 1] = P[i, colsum(runningsum(y[P[i,]]) :< quota) + 1] }
Power = J(rows(y), 1, .) for (i = 1; i <= rows(y); i ++) { Power[i, 1] = colsum(R :== i) }
return(Power :/ n) } end
|
然后在 Stata 中运行下面的代码:
clear all do ShapleyShubik.mata lmbuild lShapleyShubik.mlib, replace
|
这样就会编译得到一个 lShapleyShubik.mlib 文件,默认会把这个文件存储到 Personal 文件夹里面。这样就不需要每次都运行下 ShapleyShubik() 函数的源代码了,可以直接使用了:
clear all mata: ShapleyShubik((40 \ 39 \ 11 \ 11), 51)
*> 1 *> +---------------+ *> 1 | .5 | *> 2 | .1666666667 | *> 3 | .1666666667 | *> 4 | .1666666667 | *> +---------------+
|
也可以把这个 mlib 文件发送给别人使用,而且不会暴露源代码,这也是代码加密的一种方法。
*- 拷贝到当前文件夹里面 copy "`c(sysdir_personal)'/lShapleyShubik.mlib" lShapleyShubik.mlib, replace
|
点击这里跳转到 RStata 短书平台获取附件:名师讲堂|使用 Stata 计算 Shapley-Shubik 权力指数:以上市公司前 10 大股东份额数据为例
评论