4

我有一个带有风险数字的投资组合数据框。我想通过下面数据框中的“端口”列进行分组,然后用该投资组合组的中位数替换“风险”列中大于其组的 95% 分位数的值

df =

    Date           Port       Risk
   2019-04-30        a         21.8
   2019-03-29        a         22.6
   2019-02-28        a         500
   2019-01-31        a         26.1
   2019-04-30        b         36.4
   2019-03-29        b         43.3
   2019-02-28        b         40
   2019-01-31        b         364

我尝试了在stackoverflow上找到的以下代码,但它不起作用。

def replace(group):
    q = group.quantile(0.95)
    outlier = group>q
    group[outlier] = group.median()
    return group

    df.groupby('Port').transform(replace)

也试过

q = pd.DataFrame(df.groupby('Port')['Risk'].quantile(0.95))
df.loc[(((q.loc[df.Port,'Risk']<df['Risk'].values)))]=q.loc[df.Port,'Risk']

预期结果是将端口“a”的第三条记录替换为组“a”的中位数为 22.2,端口“b”的第四条记录替换为组“b”的中位数为 41.6

df =

    Date           Port       Risk
   2019-04-30        a         21.8
   2019-03-29        a         22.6
   2019-02-28        a         22.2
   2019-01-31        a         26.1
   2019-04-30        b         36.4
   2019-03-29        b         43.3
   2019-02-28        b         40
   2019-01-31        b         41.6
4

3 回答 3

3

要坚持您发布的代码:

def replace(group):
    q = group.quantile(0.95)
    outlier = group>q
    group[outlier] = group.median()
    return group

df['Risk'] = (df.groupby('Port').transform(replace))
print(df)

输出:

         Date Port   Risk
0  2019-04-30    a  21.80
1  2019-03-29    a  22.60
2  2019-02-28    a  24.35
3  2019-01-31    a  26.10
4  2019-04-30    b  36.40
5  2019-03-29    b  43.30
6  2019-02-28    b  40.00
7  2019-01-31    b  41.65
于 2019-05-16T19:46:54.190 回答
2

中位数似乎与您所说的略有不同(请参阅输出数据框中的注释)。GroupBy.transform这是使用with的一种方法where

g = df.groupby('Port').Risk
df['Risk'] = (df.Risk.where(g.transform('quantile', q=0.95) > df.Risk, 
                            g.transform('median')))

      Date     Port  Risk
0  2019-04-30    a  21.80
1  2019-03-29    a  22.60
2  2019-02-28    a  24.35 # -> np.median([21.8, 22.6, 500, 26.1]) = 24.35
3  2019-01-31    a  26.10
4  2019-04-30    b  36.40
5  2019-03-29    b  43.30
6  2019-02-28    b  40.00
7  2019-01-31    b  41.65
于 2019-05-16T19:44:57.120 回答
1

这是一种方法:

df = pd.DataFrame({"Port" : ['a', 'a', 'a', 'a', 'b', 'b', 'b' ,'b'],
    "Risk" : [21.8, 22.6, 500, 26.1, 36.4,43.3,40,364]
})

for port in df['Port'].unique():
    mask_port = df['Port'] == port
    quantile_port = df[mask_port].quantile(0.95)
    median_port = df[mask_port].median()
    df.loc[(mask_port) & (df['Risk']>quantile_port.Risk), 'Risk'] = median_port.Risk

In [1] : print(df)
Out[1] :   Port   Risk
0    a  21.80
1    a  22.60
2    a  24.35
3    a  26.10
4    b  36.40
5    b  43.30
6    b  40.00
7    b  41.65
于 2019-05-16T19:59:02.847 回答