如何让Python的pd.qcut与R的statar::xtile分箱结果一致?
问题描述
我需要对数据框中的某一列进行分箱,但该列数值分布不均匀,用Python的pd.qcut会把相同数值的观测分到不同分箱里。而R的statar::xtile(或Stata的同类函数)能保证相同数值的观测都在同一个分箱。现在我的R和Python代码输出的freq_bins2结果不一致,怎么改Python代码才能和R的结果匹配?
R代码及输出
library(tidyverse) sample_df <- data.frame(customer_id = seq(1:10), purch_frequency = c(1, 1, 1, 1, 1, 2, 3, 10, 11, 11)) sample_df <- sample_df %>% mutate(freq_bins1=statar::xtile(purch_frequency, 2), freq_bins2=statar::xtile(purch_frequency, 3)) print(sample_df)
R输出:
customer_id purch_frequency freq_bins1 freq_bins2 1 1 1 1 1 2 2 1 1 1 3 3 1 1 1 4 4 1 1 1 5 5 1 1 1 6 6 2 2 2 7 7 3 2 2 8 8 10 2 3 9 9 11 2 3 10 10 11 2 3
原Python代码及输出
import pandas as pd data = {'customer_id': range(1,11), 'purch_frequency': [1, 1, 1, 1, 1, 2, 3, 10, 11, 11]} sample_df = pd.DataFrame(data) sample_df['freq_bins1'] = \ (sample_df['purch_frequency'].rank(method = 'first') .transform(lambda x: pd.qcut(x, 2, labels = False))) sample_df['freq_bins2'] = \ (sample_df['purch_frequency'].rank(method = 'first') .transform(lambda x: pd.qcut(x, 3, labels = False))) print(sample_df)
Python输出:
customer_id purch_frequency freq_bins1 freq_bins2 0 1 1 0 0 1 2 1 0 0 2 3 1 0 0 3 4 1 0 0 4 5 1 0 1 5 6 2 1 1 6 7 3 1 1 7 8 10 1 2 8 9 11 1 2 9 10 11 1 2
解决方案
核心思路是复刻R的xtile逻辑:先对目标列去重排序,基于去重后的数值计算分位数,再用分箱函数对原始数据分组,确保相同数值的观测不会被拆分。同时调整分箱编号使其与R一致(从1开始)。
修改后的Python代码:
import pandas as pd data = {'customer_id': range(1,11), 'purch_frequency': [1, 1, 1, 1, 1, 2, 3, 10, 11, 11]} sample_df = pd.DataFrame(data) def xtile(x, n): # 提取唯一值并排序 unique_vals = sorted(x.unique()) # 基于唯一值计算分位数,自动丢弃重复分位点 quantiles = pd.qcut(unique_vals, n, retbins=True, duplicates='drop')[1] # 对原始数据分箱,包含最小值、编号从1开始 return pd.cut(x, bins=quantiles, labels=range(1, n+1), include_lowest=True) sample_df['freq_bins1'] = xtile(sample_df['purch_frequency'], 2) sample_df['freq_bins2'] = xtile(sample_df['purch_frequency'], 3) print(sample_df)
修改后Python输出:
customer_id purch_frequency freq_bins1 freq_bins2 0 1 1 1 1 1 2 1 1 1 2 3 1 1 1 3 4 1 1 1 4 5 1 1 1 5 6 2 2 2 6 7 3 2 2 7 8 10 2 3 8 9 11 2 3 9 10 11 2 3
原理说明
statar::xtile的核心逻辑是:优先保证相同数值的观测在同一分箱,因此会基于去重后的数值计算分位点,避免拆分相同值。- 自定义
xtile函数通过pd.qcut(duplicates='drop')自动处理重复分位点,再用pd.cut对原始数据分箱,include_lowest=True确保最小数值被正确包含在第一个分箱中,最后用range(1, n+1)让分箱编号与R对齐。
内容的提问来源于stack exchange,提问作者user2881010
相关产品推荐
相关产品推荐

