`groupby` - `qcut` 但有条件

`groupby` - `qcut` but with condition

我有一个数据框如下:

   key1 key2  val
0     a    x    8
1     a    x    6
2     a    x    7
3     a    x    4
4     a    x    9
5     a    x    1
6     a    x    2
7     a    x    3
8     a    x   10
9     a    x    5
10    a    y    4
11    a    y    9
12    a    y    1
13    a    y    2
14    b    x   17
15    b    x   15
16    b    x   18
17    b    x   19
18    b    x   12
19    b    x   20
20    b    x   14
21    b    x   13
22    b    x   16
23    b    x   11
24    b    y    2
25    b    y    3
26    b    y   10
27    b    y    5
28    b    y    4
29    b    y   24
30    b    y   22

我需要做的是:

  1. 通过key1
  2. 访问每个组
  3. 在每组 key1 中,我需要对 key2 == x
  4. 的观察结果进行 qcut
  5. 对于那些超出 bin 范围的观测值,将它们分配给最低和最高的 bins

根据上面的数据框,第一组 key1 = a 来自 indx=0-13。但是,只有 0-9 的索引用于创建 bins(阈值)。然后从 indx=0-13

应用 bins(threshold)

然后第二组 key1 = b 来自 indx=14-30。只有 14-23 的 indx 用于创建 bins(阈值)。然后从 indx=14-30.

应用 bins(threshold)

但是,从 indx=24-28 到 indx=29-30,它们超出了 bin 范围。然后对于 indx=24-28 分配给最小的 bin 范围,indx=29-30 分配给最大的 bin 范围。

输出如下所示:

   key1 key2  val  labels
0     a    x    8          1
1     a    x    6          1
2     a    x    7          1
3     a    x    4          0
4     a    x    9          1
5     a    x    1          0
6     a    x    2          0
7     a    x    3          0
8     a    x   10          1
9     a    x    5          0
10    a    y    4          0
11    a    y    9          1
12    a    y    1          0
13    a    y    2          0
14    b    x   17          1
15    b    x   15          0
16    b    x   18          1
17    b    x   19          1
18    b    x   12          0
19    b    x   20          1
20    b    x   14          0
21    b    x   13          0
22    b    x   16          1
23    b    x   11          0
24    b    y    2          0
25    b    y    3          0
26    b    y   10          0
27    b    y    5          0
28    b    y    4          0
29    b    y   24          1
30    b    y   22          1

我的解决方案: 我创建了一个 dict 来包含垃圾箱:(为简单起见,取 qcut=2)

dict_bins = {}
key_unique = data['key1'].unique()
for k in key_unique:
    sub = data[(data['key1'] == k) & (data['key2'] == 'x')].copy()
    dict_bins[k] = pd.qcut(sub['val'], 2, labels=False, retbins=True )[1]

然后,我打算将 groupbyapply 一起使用,但在访问 dict_bins

时卡住了
data['sort_key1'] = data.groupby(['key1'])['val'].apply(lambda g: --- stuck---)

感谢任何其他解决方案或对我的解决方案的修改。

谢谢

第一种方法是创建自定义函数:

def discretize(df):
    bins = pd.qcut(df.loc[df['key2'] == 'x', 'val'], 2, labels=False, retbins=True)[1]
    bins = [-np.inf] + bins[1:-1].tolist() + [np.inf]
    return pd.cut(df['val'], bins, labels=False)

df['label'] = df.groupby('key1').apply(discretize).droplevel(0)

输出:

>>> df
   key1 key2  val  label
0     a    x    8      1
1     a    x    6      1
2     a    x    7      1
3     a    x    4      0
4     a    x    9      1
5     a    x    1      0
6     a    x    2      0
7     a    x    3      0
8     a    x   10      1
9     a    x    5      0
10    a    y    4      0
11    a    y    9      1
12    a    y    1      0
13    a    y    2      0
14    b    x   17      1
15    b    x   15      0
16    b    x   18      1
17    b    x   19      1
18    b    x   12      0
19    b    x   20      1
20    b    x   14      0
21    b    x   13      0
22    b    x   16      1
23    b    x   11      0
24    b    y    2      0
25    b    y    3      0
26    b    y   10      0
27    b    y    5      0
28    b    y    4      0
29    b    y   24      1
30    b    y   22      1

您需要删除第一级索引以对齐索引:

>>> df.groupby('key1').apply(discretize)
key1  # <- you have to drop this index level
a     0     1
      1     1
      2     1
      3     0
      4     1
      5     0
      6     0
      7     0
      8     1
      9     0
      10    0
      11    1
      12    0
      13    0
b     14    1
      15    0
      16    1
      17    1
      18    0
      19    1
      20    0
      21    0
      22    1
      23    0
      24    0
      25    0
      26    0
      27    0
      28    0
      29    1
      30    1
Name: val, dtype: int64