我有一组垃圾箱,可以通过以下方式定义:
每个bin的一组非重叠边界元组:
间隔:[(0,1),(1,2),(3,4)]
一组标识每个元组的哪个边界闭合的指示器:
Closed_Boundaries:['正确','正确','都']
每个间隔的一组标签
标签:['第一','第二','第三']
我正在寻找一种有效,优雅且可扩展的方法,将该分箱方法应用于熊猫数据框中的数字序列,以使结果包括分箱逻辑所标识的各个标签:
数据输入:[3.5、1、0.5、3]
数据结果:[“第三”,“第一”,“第一”,“第三”]
我尝试使用pandas.IntervalIndex.from_tuples(),然后使用pandas.cut()。但是,使用IntervalIndex.from_tuples()时,pandas.cut()的labels参数被禁用,而后者的name参数不允许我设置将标签用作替换值。
PS:IntervalIndex不支持带有标签的熊猫问题已经here进行了讨论。
答案 0 :(得分:1)
最简单的方法是使用pd.cut
。但是,有一个outstanding bug在labels
为bins
时会忽略IntervalIndex
。
def cut(array, bins, labels, closed='right'):
_bins = pd.IntervalIndex.from_tuples(bins, closed=closed)
x = pd.cut(array, _bins)
x.categories = labels # workaround for the bug
return x
array = [3.5, 1, 0.5, 3]
bins = [(0,1), (1,2), (3,4)]
labels = ['first', 'second', 'third']
df = pd.DataFrame({
'value': array,
'category': cut(array, bins, labels, closed='right')
})
输出:
value category
0 3.5 third
1 1.0 first
2 0.5 first
3 3.0 NaN
事情变得很慢,因为代码不是矢量化的,但是从概念上讲很简单:对于数组中的每个项目,找到它所属的第一个容器并添加该容器的标签。
def cut(array, bins, labels):
intervals = [pd.Interval(*b) for b in bins]
categories = []
for value in array:
cat = None
for i, interval in enumerate(intervals):
if value in interval:
cat = labels[i]
break
categories.append(cat)
return categories
cut([3.5, 1, 0.5, 3], bins=[(0,1,'right'),(1,2,'right'),(3,4,'left')], labels=['first', 'second', 'third'])
我修改了bin元组以包括封闭它们的哪一侧。选项为left
,right
,both
和neither
。