【问题标题】:Group by one column to assign quantiles based on another column [duplicate]按一列分组以根据另一列分配分位数[重复]
【发布时间】:2021-08-28 16:54:24
【问题描述】:

这是我的数据的可复制示例。假设我在df 中存储了以下pandas.DataFrame

# Import libraries
import numpy as np
import pandas as pd
from scipy import stats

# 1K observations from two random variables
X1 = stats.norm(loc=20000, scale=5000).rvs(1000, random_state=123)
X2 = stats.norm(loc=1500, scale=300).rvs(1000, random_state=123)
df = pd.DataFrame({'id':range(1000), 'v1':X1, 'v2':X2})

# Assign deciles according to `v1`
df['v1_bin'] = pd.qcut(x=df['v1'], q=10, labels=False)
print(df.head())

   id            v1           v2  v1_bin
0   0  14571.846983  1174.310819       1
1   1  24986.727233  1799.203634       8
2   2  21414.892490  1584.893549       6
3   3  12468.526430  1048.111586       0
4   4  17106.998740  1326.419924       2

我现在想按v1_bin 分组,并根据v2 将每个组分成自己的十分位数。

我尝试了以下方法:

### Attempt
# Group by 'v1_bin' and assign deciles according to `v2`
df['v2_bin'] = df.groupby('v1_bin')['v2'].quantile(np.arange(0.1, 1.1, 0.1))

v1_bin     
0       0.1     772.493815
        0.2     867.479244
        0.3     922.716877
        0.4     960.185441
        0.5     984.500809
                  ...

但是,最后一行返回 100 个值,代表每个十分位数的上限。我想要每个观察的标签。也就是说,1000 个值,每个都有自己的标签。

换句话说,我希望我的决赛桌看起来像这样(注意v2_bin 中的标签是虚构的):

   id            v1           v2  v1_bin  v2_bin
0   0  14571.846983  1174.310819       1       1
1   1  24986.727233  1799.203634       8       1
2   2  21414.892490  1584.893549       6       0
3   3  12468.526430  1048.111586       0       1
4   4  17106.998740  1326.419924       2       4

如何做到这一点?

【问题讨论】:

  • 我投票结束我自己的问题。还有另一个线程here,我没有意识到。

标签: python pandas


【解决方案1】:

使用groupby transform 再次尝试qcut

df['v2_bin'] = (
    df.groupby('v1_bin')['v2']
        .transform(lambda g: pd.qcut(g, q=10, labels=False))
)

df.head():

   id            v1           v2  v1_bin  v2_bin
0   0  14571.846983  1174.310819       1       5
1   1  24986.727233  1799.203634       8       4
2   2  21414.892490  1584.893549       6       3
3   3  12468.526430  1048.111586       0       7
4   4  17106.998740  1326.419924       2       8

【讨论】:

  • 谢谢!您能否简要解释一下transform 的作用以及为什么它对 lambda 是必要的?
  • 所以实际上transformapply 都在这里工作。所以基本上我们只是在每个组上执行qcut。我选择transform 的惯用原因是我们将每组“v2”转换为分位数。将数据传递给transformapply 的方式也有好处。但这里有很多很好的信息:Apply vs transform on a group object,详细说明了两种可能选项之间的差异。
【解决方案2】:

这里是手工制作的版本:

new_bins = [] 
for i in df["v1_bin"].unique(): 
    new_bins.append(pd.qcut(x=df[df["v1_bin"] == i]["v2"], q=10, labels=False)) 
 
df["v2_bin"]=pd.concat(new_bins, axis=0).sort_index() 
df  

          id            v1           v2  v1_bin  v2_bin
0      0  14571.846983  1174.310819       1       5
1      1  24986.727233  1799.203634       8       4
2      2  21414.892490  1584.893549       6       3
3      3  12468.526430  1048.111586       0       7
4      4  17106.998740  1326.419924       2       8
..   ...           ...          ...     ...     ...
995  995  23173.815658  1690.428939       7       4
996  996  25349.592995  1820.975580       8       6
997  997  15453.364917  1227.201895       1       9
998  998  22351.318738  1641.079124       7       0
999  999  14442.847761  1166.570866       1       4

【讨论】:

    猜你喜欢
    • 2022-01-07
    • 2021-02-03
    • 1970-01-01
    • 2017-08-12
    • 2019-08-29
    • 2022-11-19
    • 1970-01-01
    • 2020-12-11
    • 2018-09-09
    相关资源
    最近更新 更多