Python相当于Excel的PERCENTILE.EXC

时间:2016-07-26 17:13:27

标签: python pandas

我正在使用Pandas来计算一些财务风险分析,包括风险价值。简而言之,要计算风险价值(VaR),您需要计算模拟投资组合价值变化的时间序列,然后计算特定的尾部百分位数损失。例如,95%的VaR是该时间序列中的第5百分位数。

我在Pandas数据框中有时间序列,目前正在使用pd.quantile()函数来计算百分位数。我的问题是,VaR的典型市场惯例是使用排他性百分位数(即:95%VaR被解释为:您的投资组合有95%的可能不会超过计算数量) - 类似于MS Excel PERECENTILE.EXC ()有效。 Pandas quantile()的工作方式类似于Excel的PERCENTILE.INC()的工作方式 - 它包含指定的百分位数。我已经搜索了几个python数学包以及这个论坛的python解决方案,使用与Excel中的PERCENTILE.EXC()相同的方法,没有运气。我希望有人在这里提出建议吗?

以下是示例代码。

import pandas as pd
import numpy as np

test_pd = pd.Series([15,14,18,-2,6,-78,31,21,98,-54,-2,-36,5,2,46,-72,3,-2,7,9,34])
test_np = np.array([15,14,18,-2,6,-78,31,21,98,-54,-2,-36,5,2,46,-72,3,-2,7,9,34])

print 'pandas: ' + str(test_pd.quantile(.05))
print 'numpy: '+ str(np.percentile(test_np,5))

我要找的答案是-77.4

谢谢,

赖安

3 个答案:

答案 0 :(得分:3)

它不会像熊猫自己的百分位那样有效,但它应该有效:

def quantile_exc(ser, q):
    ser_sorted = ser.sort_values()
    rank = q * (len(ser) + 1) - 1
    assert rank > 0, 'quantile is too small'
    rank_l = int(rank)
    return ser_sorted.iat[rank_l] + (ser_sorted.iat[rank_l + 1] - 
                                     ser_sorted.iat[rank_l]) * (rank - rank_l)

ser = pd.Series([15,14,18,-2,6,-78,31,21,98,-54,-2,-36,5,2,46,-72,3,-2,7,9,34])

quantile_exc(ser, 0.05)
Out: -77.400000000000006

quantile_exc(ser, 0.1)
Out: -68.399999999999991

quantile_exc(ser, 0.3)
Out: -2.0

请注意,Excel会因小百分位数而失败;这不是一个bug。这是因为低于最小值的等级不适合插值。所以你可能想检查排名> quantile_exc函数中的0(参见断言部分)。

答案 1 :(得分:2)

编辑:我刚看到你的编辑。我认为你犯了一个错误。值-77.4实际上是您数据的99.5%百分位数。试试test_pd.quantile(.005)。我相信在指定百分位数时你必须在Excel中犯了错误。

编辑2:我刚在Excel中测试过它。对于第50个百分点,我在Excel和Numpy / Pandas中获得正确的值。然而,对于第5个百分点,我在Pandas / Numpy中获得-72,在Excel中获得-74.6。但Excel在这里是错的:很明显-74.6是第0.5百分位,而不是第5个......

最终编辑:经过一些测试后,似乎Excel使用PERCENTILE.EXC()函数在非常小的k值周围表现不正常。实际上,使用任何k PERCENTILE.EXC(0.5) = 6和test_pd.quantile(0.5) = 6也是如此。我想教训我们需要警惕Excel的行为;)。

我理解您的问题的方式是:您想知道与您的数据的第k百分位数相对应的值,排除此第k个百分位数。但是,pd.quantile()会返回与您的第k百分位数对应的值,包括此第k个百分位数。

我不认为pd.quantile()返回包含的第k个百分位是一个问题。实际上,假设您希望所有股票的风险价值严格高于第5个百分点,您可以这样做:

mask = data["VaR"] < pd.quantile(data["VaR"], 0.05)
data_filt = data[mask]

因为您使用了“小于”(&lt;)运算符,所以将排除与您的第5个百分位数完全对应的值,类似于Excel的PERCENTILE.EXC()函数。

请告诉我这是否是你要找的。

答案 2 :(得分:0)

似乎包Percentileorg.apache.commons.math3.stat.descriptive.rank函数的实现与Excel中的PERCENTILE.EXC函数有联系。

下面是带有一些细微调整的Python实现。

rowpandas.Series

    row_sorted = row.sort_values()
    n = len(row_sorted)
    # index start from 0 so we need to -1
    pos = quantile * (n + 1) - 1
    # If pos < 0 return the smallest element in the array.
    if pos < 0:
        var = row_sorted.iat[0]
    # Else if pos >= n - 1 return the largest element in the array.
    if pos >= n - 1:
        var = row_sorted.iat[n - 1]
    # floor(pos)
    pos_lower = int(pos)
    # the fractional part of pos
    d = pos - pos_lower
    # the next element index
    pos_upper = pos_lower + 1
    # calculate var
    lower = row_sorted.iat[pos_lower]
    upper = row_sorted.iat[pos_upper]
    var = lower + (upper - lower) * d