提问人:chroberts 提问时间:11/18/2023 更新时间:11/18/2023 访问量:33
在 Pandas 中,如何对其他列的字符串类型进行 bin 浮点数和计数,其中 bin 是恒定大小的滚动、重叠数值范围?
In Pandas, how do I bin floats and count string types from other cols where the bin is of a rolling, overlapping numeric range of constant size?
问:
我有一个浮点值和字符串表,如下所示:
FltVal | 类别 |
---|---|
0.01 | 一个 |
0.02 | 一个 |
0.05 | B |
0.31 | B |
0.36 | 一个 |
0.37 | C |
0.41 | B |
我想生成一个新的数据帧,该数据帧将浮点值装箱到大小为 0.3 的箱中(因此每个箱都是 (x, x + 0.3]),并以 0.01 的增量重叠。此外,我想要一列来计算进入垃圾箱的记录数,以及一列统计垃圾箱的每个“类别”总数。
我首先尝试使用 groupby 和 pd.cut 进行基本计数(在尝试查找每个类别的计数之前):
import pandas as pd
floats = pd.Series([0.01,0.02,0.05,0.31,0.36,0.37,0.41])
categories = pd.Series(['A','A','B','B','A','C','B'])
data = {"FltVal": floats, "Category": categories}
df = pd.concat(data, axis=1)
grouped_vals = df.groupby(pd.cut(df['FltVal'],np.arange(df['FltVal'].min(),df['FltVal'].max(),0.3))).count()
输出:
FltVal Category
FltVal
(0.01, 0.31] 3 3
我认为问题在于它不能考虑另一个垃圾箱,更不用说重叠了?
然后,有了这个想法,我可以在之后抛出不合理的(如负数)范围,我尝试了以下方法:
FltVal_range = np.arange(df['FltVal'].min(),df['FltVal'].max(),0.01)
FltVal_range_from = FltVal_range - 0.3
FltVal_range_to = FltVal_range
FltVal_intervals = pd.IntervalIndex.from_arrays(FltVal_range_from,FltVal_range_to)
binned_df = df.groupby(pd.cut(df['FltVal'], FltVal_intervals))
但是得到了 ValueError 消息:
Overlapping IntervalIndex is not accepted.
如果 pd.cut 不接受重叠的垃圾箱,我想这是一个不可行的。
无论如何,所需的输出如下:
浮点仓 | 计数 | Cat_A | Cat_B | Cat_C |
---|---|---|---|---|
0.00, 0.30 | 3 | 2 | 1 | 0 |
0.01, 0.31 | 3 | 1 | 2 | 0 |
0.02, 0.32 | 2 | 0 | 2 | 0 |
0.03, 0.33 | 2 | 0 | 2 | 0 |
0.04, 0.34 | 2 | 0 | 2 | 0 |
0.05, 0.35 | 1 | 0 | 1 | 0 |
0.06, 0.36 | 2 | 1 | 1 | 0 |
0.07, 0.37 | 3 | 1 | 1 | 1 |
0.08, 0.38 | 3 | 1 | 1 | 1 |
0.09, 0.39 | 3 | 1 | 1 | 1 |
0.1, 0.4 | 3 | 1 | 1 | 1 |
0.11, 0.41 | 4 | 1 | 2 | 1 |
一种有效的方法是必要的,因为实际的数据帧将有数十万到数百万的行。
我正在考虑与此答案类似的东西,但适合查找我所有类别的计数。
非常感谢所有的帮助!
答:
1赞
mozway
11/18/2023
#1
使用 conditional_join
的一个选项:janitor
import janitor
FltVal_range = np.arange(df['FltVal'].min(), df['FltVal'].max(), 0.01)
tmp = (pd.crosstab(df['FltVal'], df['Category'],
margins=True, margins_name='Count')
.drop('Count')
)
out = (pd.DataFrame({'low': FltVal_range, 'high': FltVal_range+0.3})
.conditional_join(tmp.reset_index(),
('low', 'FltVal', '<'),
('high', 'FltVal', '>='))
.groupby(['low', 'high'])[list(tmp)].sum()
)
输出:
A B C Count
low high
0.01 0.31 1 2 0 3
0.02 0.32 0 2 0 2
0.03 0.33 0 2 0 2
0.04 0.34 0 2 0 2
0.05 0.35 0 1 0 1
0.06 0.36 1 1 0 2
0.07 0.37 1 1 1 3
0.08 0.38 1 1 1 3
0.09 0.39 1 1 1 3
0.10 0.40 1 1 1 3
0.11 0.41 1 2 1 4
0.12 0.42 1 2 1 4
0.13 0.43 1 2 1 4
0.14 0.44 1 2 1 4
0.15 0.45 1 2 1 4
...
评论
0赞
chroberts
11/23/2023
谢谢,它有效!如果您有一个没有其他依赖项的解决方案,那么其他人也会感到好奇。
0赞
mozway
11/23/2023
@chroberts我不认为有一种纯粹的熊猫方式会如此有效。不幸的是,pandas 没有内置的基于非精确匹配的多对多合并函数。
评论