如何创建具有非唯一bin边的分位数?Python或R



我想将数据划分为分位数(更具体地说是分位数(。然而,当在Pandas中使用qcut或在R中使用ntile时,我得到的错误是";仓边缘必须是唯一的";(qcut(或相等的值被分配给不同的五分位数(ntile(。

查看以下数据:[1,8,2,1,8]我希望输出为:

  • 1分配到五分之一
  • 8人被分配到5分之一
  • 2被分配到五等分3
  • 1再次被分配到五分之一
  • 8再次被分配到5分之一

在这种特殊情况下,1也可以分配给五分位数2,而不是1(取决于定义(。同样重要的是,为同一个五分位数分配相等的值。

你对我如何做到这一点有什么想法吗?

非常感谢您的投入!

要使用的一些数据:

import pandas as pd
df = pd.DataFrame({'Date': ['2011-01-01', '2011-01-02', '2011-01-03','2011-01-01', '2011-01-02', 
'2011-01-03','2011-01-01', '2011-01-02', '2011-01-03', '2011-01-01','2011-01-02', '2011-01-03',
'2011-01-01', '2011-01-02', '2011-01-03'], 'Name': ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C', 'D', 'D', 'D', 'E', 'E', 'E'], 
'Value':[1, 3, 2, 8, 6, 5, 2, 10, 4, 1, 5, 3, 8, 4, 9]})

我在R:中使用的代码

df = df %>% group_by(Date) %>% mutate(Quint = ntile(Value, 5)) 

这为不同的仓分配了相等的值。

我在Python中使用的代码:

df['Quintiles'] = df.groupby(by=["Date"])['Value'].transform(lambda x: pd.qcut(x, 5, labels=["XS", "S", "M", "L", "XL"]))

这导致仓边缘必须是唯一的错误。

更新

在这种特定情况下,1也可以分配给五分位数2,而不是1(取决于定义(。同样重要的是,为同一个五分位数分配相等的值。

cut_rank = lambda x: pd.cut(x.rank(method='min'), 5, labels=["XS", "S", "M", "L", "XL"])
df['Quintiles'] = df.groupby(by=["Date"])['Value'].transform(cut_rank)

输出:

>>> df[df['Date'] == '2011-01-01']
Date Name  Value Quintiles
0   2011-01-01    A      1        XS
3   2011-01-01    B      8        XL
6   2011-01-01    C      2         L
9   2011-01-01    D      1        XS
12  2011-01-01    E      8        XL
>>> df
Date Name  Value Quintiles
0   2011-01-01    A      1        XS
1   2011-01-02    A      3        XS
2   2011-01-03    A      2        XS
3   2011-01-01    B      8        XL
4   2011-01-02    B      6         L
5   2011-01-03    B      5         L
6   2011-01-01    C      2         L
7   2011-01-02    C     10        XL
8   2011-01-03    C      4         M
9   2011-01-01    D      1        XS
10  2011-01-02    D      5         M
11  2011-01-03    D      3         S
12  2011-01-01    E      8        XL
13  2011-01-02    E      4         S
14  2011-01-03    E      9        XL

旧答案

qcut:之前,您必须在每组上使用rankmethod='first'

qcut_rank = lambda x: pd.qcut(x.rank(method='first'), 5, labels=["XS", "S", "M", "L", "XL"])
df['Quintiles'] = df.groupby(by=["Date"])['Value'].transform(qcut_rank)

输出:

>>> df
Date Name  Value Quintiles
0   2011-01-01    A      1        XS
1   2011-01-02    A      3        XS
2   2011-01-03    A      2        XS
3   2011-01-01    B      8         L
4   2011-01-02    B      6         L
5   2011-01-03    B      5         L
6   2011-01-01    C      2         M
7   2011-01-02    C     10        XL
8   2011-01-03    C      4         M
9   2011-01-01    D      1         S
10  2011-01-02    D      5         M
11  2011-01-03    D      3         S
12  2011-01-01    E      8        XL
13  2011-01-02    E      4         S
14  2011-01-03    E      9        XL

所有解释都在这里

这是一个部分答案,因为它着眼于numpy对百分位数插值方法的描述,而不是直接应用于pandas,但在上面的手册中,您可以看到不连续数据集的百分位数的不同插值选项。

import numpy as np
x =  [1, 8, 2, 1, 8]
discontinuous_methods = ['linear',
'lower',
'higher',
'midpoint',
'nearest']
for method in discontinuous_methods:
n = [f'{np.percentile(x, i, interpolation = method):.2f}' for i in [20, 40, 60, 80]]
print(f'{method:8s} - {n[0]:3s}, {n[1]:3s}, {n[2]:3s}, {n[3]:3s}')
linear   - 1.00, 1.60, 4.40, 8.00
lower    - 1.00, 1.00, 2.00, 8.00
higher   - 1.00, 2.00, 8.00, 8.00
midpoint - 1.00, 1.50, 5.00, 8.00
nearest  - 1.00, 2.00, 2.00, 8.00

最新更新