我想做的事
我有一个长格式的pandas DataFrame,包含不同组的值。我想计算并应用基于分位数的装箱(例如,本例中的五分位数)到DataFrame的每个组。
我还需要能够保留每个组的bin边缘,并将相同的标签(通过pd.cut
)应用于新的DataFrame。
例如,对于每个组,找到五分位数并将其分配给新的列value_label
。
import numpy as np
import pandas as pd
df1 = pd.DataFrame({"group": "A", "val": np.random.normal(loc=10, scale=5, size=100)})
df2 = pd.DataFrame({"group": "B", "val": np.random.normal(loc=5, scale=3, size=100)})
df = pd.concat([df1, df2], ignore_index=True)
# apply qcut
labels_and_bins = df.groupby("group")["val"].apply(
lambda x: pd.qcut(x, q=5, duplicates="drop", retbins=True)
)
# where e.g.
labels_and_bins["A"][0] # are the applied labels to all the rows in group "A"
labels_and_bins["A"][1] # are the bin edges to apply the same segmentation going forward
for group in df.group.unique():
df.loc[df["group"] == group, "value_label"] = labels_and_bins[group][0]
当我尝试运行它时,在第二次迭代时,我得到了以下错误:TypeError: Cannot set a Categorical with another, without identical categories
因此,本质上我需要Pandas接受扩展属于列dtype的类别。
我考虑过的
变形
使用.transform()
可能会解决在第一个DataFrame上分配标签的问题,但我不清楚如何在未来的迭代中重用已标识的bin
联合分类dtype
我尝试了两种方法:
add_categories()
labels_and_bins['A'][0].cat.add_categories(labels_and_bins['B'][0].cat.as_unordered())
结果为ValueError: Categorical categories must be unique
union_categoricals()
pd.api.types.union_categoricals(
[labels_and_bins["A"][0].cat.as_unordered(), labels_and_bins["B"][0].cat.as_unordered()].get_inde
)
结果为InvalidIndexError: cannot handle overlapping indices; use IntervalIndex.get_indexer_non_unique
一个解决方案
通过调用不带标签的qcut来摆脱Interval对象,例如:
labels_and_bins = df.groupby("group")["val"].apply(
lambda x: pd.qcut(x, q=5, duplicates="drop", retbins=True, labels=False)
)
然而,如果可能的话,为了更好的解释性,我会对保持间隔的方法感兴趣
总的来说,这感觉像是一个大的反模式,所以我相信我错过了这个问题的一个更基本的解决方案!
提前感谢您的输入!
3条答案
按热度按时间vlju58qv1#
你可以使用
groupby(...).quantile
来获取你的bins。获取标签是一个棘手的部分,如果你想拥有cut
和qcut
返回的相同类型的标签,你可以将这个结果转换为pandas.arrays.IntervalArray
,然后从那里抓取左边缘。在这里,您可以使用
pd.merge_asof
将您的bin与其他数据集对齐,甚至可以返回到原始的DataFrame
!eni9jsuy2#
如果我理解正确的话,你可以用chain来实现:
gpnt7bae3#
我认为你想达到的目标是:
这给予了你原始的df
新的一个: