在指数估值时,需要计算当前指数估值在历史估值中的分位值,以判断当前估值的位置。本人在计算分位值时,使用过的的函数有excel的PERCENTRANK、PERCENTRANK.INC、PERCENTRANK.EXC和python的stats.percentileofscore、以及利用bisect.bisect+线性插值,以上函数计算结果并不一致。当然,在实际使用时,模糊的正确即可。本文只是想搞清楚结果不一致的原因。
问题描述为求某个数值x在数列a={a[i]}(i=1,2,...)中的百分比排位。为了表述的方便,假设数列a为从小到大排序的有序数列。 结论: 当a包含x,且a中数值较多时,函数scipy.stats.percentileofscore(a, x, kind='strict 39;;)与函数PERCENTRANK(a,x,[significance])计算结果趋同。但若a中存在较多与x相等的值时,可能存在低估风险。 具体研究过程: scipy.stats.percentileofscore(a, x, kind='rank 39;) kind的取值包括rank、weak、strict和mean,缺省值为rank. 当kind='rank 39;时: 计算结果=x的排序位置/数列总数 若数列中含有多个相同的x,则计算结果为每个x计算结果的平均值。 如:stats.percentileofscore([1, 2, 3, 4], 3) 计算结果为 (3/4)*100 = 75 stats.percentileofscore([1, 2, 3, 3, 4], 3) 计算结果为((3/5)*100+(4/5)*100)/2=(60+80)/2=70 当kind='weak 39;时: 计算公式同rank,分子值取a中小于等于x的个数。 如:stats.percentileofscore([1, 2, 3, 3, 4], 3, kind='weak 39;) 计算结果 (4/5)*100=80 当kind='strict 39;时: 计算公式同rank,分子值取a中小于x的个数。 如:stats.percentileofscore([1, 2, 3, 3, 4], 3, kind='strict 39;) 计算结果 (2/5)*100=40 当kind='mean 39;时: 计算公式同rank,结果取kind为'strict 39;和'weak 39;时的平均值。 如:stats.percentileofscore([1, 2, 3, 3, 4], 3, kind='mean 39;) 计算结果 ((4/5)*100 + (2/5)*100)/2 =60 当数列a不包含x时,计算结果=a中小于x的个数/数列总数。类似kind='strict 39;。 如:stats.percentileofscore([1, 2, 3, 4, 5], 1.5) 计算结果=(1/5)*100 = 20 bisect.bisect+线性插值(该方法来自@JoinQuant聚宽 用户 cjhren ) 计算思路是: 利用函数quantile计算数列a的十分位数列B;利用函数bisect.bisect计算x在数列B中的位置i;利用差值计算公式计算x在数列a中的分位。函数代码为: B = [a.quantile(i/10.0) for i in range(11)] i = bisect.bisect(B,x) quantile = i-(B[i]-x)/(B[i]-B[i-1]) 函数bisect.bisect(B,x)的计算结果等于序列B中小于等于x的个数。 如:bisect.bisect([1,2,3,4,5],3.5) =3 , bisect.bisect([1,2,3,4,5],5)=5 需要注意的是: 当数列B包含x时,如果x=max(B),i=len(B),则在利用线性插值公式时,公式B[i]的取值会溢出。故上述函数代码应添加一判断:if i==len(B):quantile = 1 当数列B不包含x时,如果x≥max(B),处理方法同上;如果x<min(B),i=0,B[i-1]=B[-1],quantile 的计算将失真。故代码还应添加一判断:if i==len(B):quantile = 1 elif i==0: quantile = 0 显然,quantile的计算精度取决于生成数列B,生成B时的分位点越密集,利用线性插值公式计算结果精度越高,极端情况B=a,则bisect.bisect(a,x)=len([i for i in a if i<=x]), quantile="">=x]),> PERCENTRANK(a,x,[significance]) PERCENTRANK 函数语法具有下列参数: a 必需。 定义相对位置的数值数组或数值数据区域。x 必需。 需要得到其排位的值。significance 可选。 用于标识返回的百分比值的有效位数的值。 如果省略,则 PERCENTRANK 使用 3 位小数 (0.xxx)。当a包含x时,计算结果=count(a PERCENTRANK.INC(array,x,[significance]) 等同于函数PERCENTRANK(a,x,[significance]) PERCENTRANK.EXC(array,x,[significance]) 百分位不包含0,1. 当a包含x时,计算结果=(count(a 另附两张中证500的PE、PB估值与分位图,估值方法中位数,分位值计算基于函数scipy.stats.percentileofscore(a, x, kind='> 德艺双馨@ETF拯救世界 ,让我的投资认知上了好几个凳次,感激不尽啊! @江州金猪 @冬日的阳光 @梧桐社 @qymu @forestgumpgg 大家都是我平时关注的基于指数估值的投资爱好者,欢迎交流指正。 最后感谢@JoinQuant聚宽 提供了优秀的量化研究平台。 |
|