pandas qcut 没有将相同数量的观察值放入每个箱子
pandas qcut not putting equal number of observations into each bin
我有一个数据框,我可以从中 select 列(系列)如下:
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 个 bin 整除的最接近的数字是 1565,这应该在每个 bin 中给出 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
每个 bin 中应该有 2 个观测值,而不是 bin 1 中的 3 个和 bin 2 中的 1 个!
qcut 正在尝试补偿重复值。如果您 return 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 中的预期值中 "steal" 一个,并将它们放在第二个 bin 中。我认为这只是在更大范围内发生在你的百分位数上,因为你基本上是将他们的排名压缩到 1 到 100 的范围内。有什么理由不直接对数据进行 运行 qcut 而不是精度更高的百分位数或 return 百分位数?
如果您必须获得相等(或几乎相等)的分箱,那么这里有一个可以与 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!
免责声明
显然,请自行决定使用它,因为结果可能会因您的数据而异;例如,您的数据集有多大 and/or 间距。上面的 "trick" 适用于整数,因为即使我们是 "salting" test_list,它仍然会在第 0 组中不会有大于的值的意义上排名顺序第 1 组中的一个值(可能相等,但不会更大)。但是,如果您有浮动,这可能会很棘手,您可能必须相应地减小噪音的大小。例如,如果你有 2.1、5.3、5.3、5.4 等浮点数,你应该通过除以 10 来减少噪声:np.random.random(len(test_list)) / 10。如果你有任意长的浮点数,但是,考虑到 "real" 数据中已经存在的噪声,您可能一开始就不会遇到这个问题。
试试下面的代码:
pd.qcut(df.rank(method='first'),nbins)
此问题是由重复值引起的。强制大小相等的 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
抱歉,我无法 post 图片,因为我在 Whosebug 上的声誉不足 10 -.-
我有一个数据框,我可以从中 select 列(系列)如下:
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 个 bin 整除的最接近的数字是 1565,这应该在每个 bin 中给出 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
每个 bin 中应该有 2 个观测值,而不是 bin 1 中的 3 个和 bin 2 中的 1 个!
qcut 正在尝试补偿重复值。如果您 return 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 中的预期值中 "steal" 一个,并将它们放在第二个 bin 中。我认为这只是在更大范围内发生在你的百分位数上,因为你基本上是将他们的排名压缩到 1 到 100 的范围内。有什么理由不直接对数据进行 运行 qcut 而不是精度更高的百分位数或 return 百分位数?
如果您必须获得相等(或几乎相等)的分箱,那么这里有一个可以与 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!
免责声明
显然,请自行决定使用它,因为结果可能会因您的数据而异;例如,您的数据集有多大 and/or 间距。上面的 "trick" 适用于整数,因为即使我们是 "salting" test_list,它仍然会在第 0 组中不会有大于的值的意义上排名顺序第 1 组中的一个值(可能相等,但不会更大)。但是,如果您有浮动,这可能会很棘手,您可能必须相应地减小噪音的大小。例如,如果你有 2.1、5.3、5.3、5.4 等浮点数,你应该通过除以 10 来减少噪声:np.random.random(len(test_list)) / 10。如果你有任意长的浮点数,但是,考虑到 "real" 数据中已经存在的噪声,您可能一开始就不会遇到这个问题。
试试下面的代码:
pd.qcut(df.rank(method='first'),nbins)
此问题是由重复值引起的。强制大小相等的 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
抱歉,我无法 post 图片,因为我在 Whosebug 上的声誉不足 10 -.-