pandas qcut没有将相同数量的观察结果放入每个箱子中

时间:2016-02-03 17:38:05

标签: python pandas binning

我有一个数据框,我可以从中选择一个列(系列),如下所示:

DF:

            value_rank
275488          90
275490          35
275491          60
275492          23
275493          23
275494          34
275495          75
275496          40
275497          69
275498          14
275499          83
...             ...

value_rank是先前从较大数据集创建的百分位数排名。我想要做的是创建这个数据集的箱子,例如五分之一

pd.qcut(df.value_rank, 5, labels=False)


275488    4
275490    1
275491    3
275492    1
275493    1
275494    1
275495    3
275496    2
...      ...

这看起来很好,正如预期的那样,但事实并非如此。

事实上,我有1569列。可被5个分区整除的最近数字是1565,这应该在每个分区中给出1565/5 = 313个观测值。有4个额外的记录,所以我期望有4个箱子有314个观测值,一个有313个观测值。相反,我得到了这个:

obs =  pd.qcut(df.value_rank, 5, labels=False)
obs.value_counts()

0    329
3    314
1    313
4    311
2    302

我在df中没有nans,也无法想出为什么会发生这种情况。从字面上开始撕掉我的头发!

这是一个小例子:

DF:

            value_rank
286742               11
286835               53
286865               40
286930               31
286936               45
286955               27
287031               30
287111               36
287269               30
287310               18

pd.qcut给出了这个:

pd.qcut(df.value_rank, 5, labels = False).value_counts()
bin  count
1    3
4    2
3    2
0    2
2    1

每个箱子中应该有2个观察值,而箱子1中不应有3个,而箱子2中应该有1个!

4 个答案:

答案 0 :(得分:3)

qcut正试图弥补重复的价值。如果您返回bin限制以及qcut结果,则可以更早地进行可视化:

In [42]: test_list = [ 11, 18, 27, 30, 30, 31, 36, 40, 45, 53 ]
In [43]: test_series = pd.Series(test_list, name='value_rank')

In [49]: pd.qcut(test_series, 5, retbins=True, labels=False)
Out[49]:
(array([0, 0, 1, 1, 1, 2, 3, 3, 4, 4]),
 array([ 11. ,  25.2,  30. ,  33. ,  41. ,  53. ]))

您可以看到除了将bin限制设置为30之外别无选择,因此qcut必须从第三个bin中的预期值“窃取”一个并将它们放在第二个bin中。我认为这只是在你的百分位数上发生的更大规模,因为你基本上将他们的等级缩小到1到100的等级。有什么理由不直接在数据上运行qcut而不是百分位或返回具有更高精度的百分位?

答案 1 :(得分:1)

如果你必须得到相同(或几乎相等)的垃圾箱,那么这里可以使用qcut。使用与接受的答案相同的数据,我们可以通过向原始test_list添加一些随机噪声并根据这些值进行分箱来强制将它们分成相等的容器。

test_list = [ 11, 18, 27, 30, 30, 31, 36, 40, 45, 53 ]

np.random.seed(42) #set this for reproducible results
test_list_rnd = np.array(test_list) + np.random.random(len(test_list)) #add noise to data

test_series = pd.Series(test_list_rnd, name='value_rank')
pd.qcut(test_series, 5, retbins=True, labels=False)

输出:

(0    0
 1    0
 2    1
 3    2
 4    1
 5    2
 6    3
 7    3
 8    4
 9    4
 Name: value_rank, dtype: int64,
 array([ 11.37454012,  25.97573801,  30.42160255,  33.11683016,
         41.81316392,  53.70807258]))

所以,现在我们有两个0,两个1,两个2和两个4&!s!

<强>声明

显然,您可以自行决定使用此项,因为结果会因您的数据而异;例如,您的数据集的大小和/或间距。以上&#34;技巧&#34;适用于整数,因为即使我们是&#34;盐渍&#34; test_list,它仍将按顺序排列顺序,即组0中的值不会大于组1中的值(可能相等,但不大于)。但是,如果你有漂浮物,这可能很棘手,你可能需要相应地减小噪音的大小。例如,如果你有像2.1,5.3,5.3,5.4等浮动,你应该减去噪音除以10:np.random.random(len(test_list))/ 10.如果你有任意长的浮点数,然而,考虑到已经存在于&#34;真实&#34;中的噪音,你可能不会首先遇到这个问题。数据

答案 2 :(得分:1)

只需尝试以下代码:

pd.qcut(df.rank(method='first'),nbins)

答案 3 :(得分:0)

这个问题是由重复值引起的。强制相等大小的 bin 的一种可能解决方案是在对数据帧进行排序后使用索引作为 pd.qcut 的输入:

import random

df = pd.DataFrame({'A': [random.randint(3, 9) for x in range(20)]}).sort_values('A').reset_index()
del df['index']
df = df.reset_index()
df['A'].plot.hist(bins=30);

图片:https://i.stack.imgur.com/ztjzn.png

df.head()
df['qcut_v1'] = pd.qcut(df['A'], q=4)
df['qcut_v2'] = pd.qcut(df['index'], q=4)
df

图片:https://i.stack.imgur.com/RB4TN.png

df.groupby('qcut_v1').count().reset_index()

图片:https://i.stack.imgur.com/IKtsW.png

df.groupby('qcut_v2').count().reset_index()

图片:https://i.stack.imgur.com/4jrkU.png

对不起,我不能发布图片,因为我在 stackoverflow 上没有至少 10 个声誉-.-