Python数据【离散化】和【逆离散化】

本文详细介绍了离散化的三种方法:等宽离散化、等频离散化及聚类,并通过实例展示了如何使用pandas进行操作。此外,还探讨了逆离散化的多种策略,包括取极值、均值以及不同类型的升采样方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、离散化

这里写图片描述

1.1、等宽离散化

1.1.1、pandas实现

pandas.cut(x, bins, right=True, labels=None)

import pandas as pd
df = pd.DataFrame({
    'Name': ['car', 'gun', 'cat'],
    'Age': [5, 2.5, 0.5]})
bins = list(range(0, 10, 2))  # 划分区间
labels = ['(%d,%d]' % (bins[i], bins[i+1]) for i in range(len(bins)-1)]  # 自定义标签:长度要-1
# 数据离散化
s1 = pd.cut(df['Age'], bins)         # [(0, 2] < (2, 4] < (4, 6] < (6, 8]]
s2 = pd.cut(df['Age'], bins, False)  # [[0, 2) < [2, 4) < [4, 6) < [6, 8)]
s3 = pd.cut(x=df['Age'], bins=bins, right=False, labels=labels)
print(s1, s2, s3, sep='\n\n')
参数解析
x被分组的数据
bins分组方式
rightTrue(default):左开右闭 False:左闭右开
labels自定义分组的标签

1.1.2、手写实现

x=[.02,.03,.05,.91,.05,.06,.01,.06,.39,.02,.13,.19,.27,.95,.02,.06,.13,.82,.89,.34,.2,.95,.02,.13,.96,.03,.05,.23,.24,
.96,.98,.03,.98,.08,.15,.2,.93,.09,.29,.97,.03,.03,.0,.95,.33,.05,.06,.86,.07,.21,.44,.67,.5,.04,.33,.05,.08,.02,.46,.49
,.68,.71,.03,.36,.38,.41,.71,.02,.98,.0,.42,.01,.16,.01,.09,.03,.36,.17,.03,.34,.94,.07,.42,.89,.04,.87,.05,.45,.9,.02,
.03,.04,.08,.81,.87,.11,.95,.06,.26,.06,.87,.04,.04,.09,.09,.91,.95,.06,.07,.09,.95,.98,.1,.84,.03,.14,.07,.03,.17,.88,
.03,.64,.03,.98,.05,.94,.02,.23,.87,.11,.83,.91,.06,.98,.04,.21,.29,.24,.83,.11,.27,.11,.41,.87,.01,.02,.17,.88,.03,.08,
.32,.11,.96,.03,.13,.18,.27,.94,.03,.18,.1,.39,.07,.27,.93,.07,.1,.82,.05,.25,.07,.04,.79,.8,.05,.06,.05,.57,.61,.63,
.04,.02,.54,.58,.62,.04,.78,.79,.01,.71,.07,.03,.02,.67,.03,.0,.02,.04,.05,.04,.0,.2,.85,.03,.13,.93,.74,.12,.9,.04,.05,
.3,.1,.93,.04,.99,.06,.05,.88,.92,.02,.16,.94,.03,.03,.18,.22,.26,.9,.02,.05,.45,.03,.03,.98,.04,.06,.91,.04,.04,.03,.5,
.89,.26,.84,.05,.12,.19,.2,.93,.06,.11,.44,.88,.9,.2,.9,.06,.95,.13,.54,.96,.01,.09,.04,.05,.05,.07,.07,.08,.03,.02,.02,
.1,.02,.27,.29,.92,.03,.24,.28,.91,.09,.64,.95,.03,.95,.02,.04,.02,.21,.15,.29,.59,.03,.35,.62,.04,.27,.31,.85,.86,.08,
.02,.99,.01,.01,.86,.04,.83,.03,.99,.01,.02,.4,.59,.64,.66,.56,.98,.05,.58,.89,.03,.96,.98,.02,.97,.01,.03,.68,.94,.05,
.99,.04,.79,.8,.22,.0,.65,.04,.11,.95,.04,.99,.46,.99,.04,.22,.48,.59,.03,.06,.08,.02,.19,.83,.04,.02,.15,.94,1.0,.05]

def discretize(x, n=20):
   bins = ['[%.2f,%.2f)' % (i / n, i / n + 1 / n) for i in range(n)]
   dt = {i: 0 for i in bins}
   for i in x:
      j = int(i // (1 / n))
      dt[bins[j]] += 1
   return dt

dt = discretize(x, n=20)
for i, j in sorted(dt.items(), reverse=True):
   print(i, '#' * j, j)

import matplotlib.pyplot as mp, seaborn
seaborn.swarmplot(y=x)
mp.show()

1.2、等频离散化

import pandas as pd
s0 = pd.Series([1, 1, 1, 2, 2, 2, 5, 5, 5, 9, 9, 9])
q = 4  # 划分区间数
s1 = pd.qcut(s0, q)
print(s1)
"""
0     (0.999, 1.75]
1     (0.999, 1.75]
2     (0.999, 1.75]
3       (1.75, 3.5]
4       (1.75, 3.5]
5       (1.75, 3.5]
6        (3.5, 6.0]
7        (3.5, 6.0]
8        (3.5, 6.0]
9        (6.0, 9.0]
10       (6.0, 9.0]
11       (6.0, 9.0]
dtype: category
Categories (4, interval[float64]): [(0.999, 1.75] < (1.75, 3.5] < (3.5, 6.0] < (6.0, 9.0]]
"""

1.3、聚类

https://blog.youkuaiyun.com/Yellow_python/article/details/81461056

2、逆离散化

2.1、取 min 和 max

import pandas as pd
df = pd.DataFrame({
    'name': ['cat', 'dog', 'tiger'],
    'price_min': [100, 10, 200],
    'price_max': [180, 90, 220]})
print(df)
# 删除列
row_min = df.pop('price_min')
row_max = df.pop('price_max')
# 重构
df_min = pd.concat([df, row_min], axis=1)
df_max = pd.concat([df, row_max], axis=1)
# 改列名
df_min.rename(columns={'price_min': 'price'}, inplace=True)
df_max.rename(columns={'price_max': 'price'}, inplace=True)
# 合并
df_mm = pd.concat([df_min, df_max])
print(df_mm)

2.2、取 min、max 和 mean

import pandas as pd
df = pd.DataFrame({
    'name': ['cat', 'dog', 'tiger'],
    'section': ['100~180', '10~90', '200~220']})
# 切分
values = df['section'].str.split('~')
# 最小值、最大值、均值
row_min = [float(i[0]) for i in values]
row_max = [float(i[1]) for i in values]
row_mean = [(row_min[i]+row_max[i])/2 for i in range(len(values))]
# 重构
df_min = pd.concat([df, pd.DataFrame(row_min, columns=['value'])], axis=1)
df_max = pd.concat([df, pd.DataFrame(row_max, columns=['value'])], axis=1)
df_mean = pd.concat([df, pd.DataFrame(row_mean, columns=['value'])], axis=1)
# 合并+排序
df_mmm = pd.concat([df_min, df_mean, df_max])
df_mmm.sort_values(by=['name', 'value'], axis=0, ascending=True, inplace=True)
print(df_mmm)

2.3、等距均匀升采样

import pandas as pd
df = pd.DataFrame({
    'name': ['cat', 'dog', 'tiger'],
    'section': ['100~190', '0~90', '200~230']})
# 切分
values = df['section'].str.split('~')
length = len(values)  # 行数
# 最大值、最小值
row_min = [float(i[0]) for i in values]
row_max = [float(i[1]) for i in values]
# 升采样(以n=3为例)
n = 3
row_ls = [row_min, row_max]
for j in range(1, n):
    row = [(row_min[i]+(row_max[i]-row_min[i])*j/n) for i in range(length)]
    row_ls.append(row)
# 重构DataFrame
df_ls = [pd.concat([df, pd.DataFrame(row, columns=['value'])], axis=1) for row in row_ls]
# 合并DataFrame、升序、重构索引
df_mm = pd.concat(df_ls)
df_mm.sort_values(by=['name', 'value'], axis=0, ascending=True, inplace=True)
df_mm.reset_index(drop=True, inplace=True)
print(df_mm)

2.4、随机均匀升采样

import pandas as pd, numpy as np
df = pd.DataFrame({
    'name': ['cat', 'tiger'],
    'section': ['0~90', '180~200']})
# 切出最小值和最大值
min_max = df['section'].str.split('~')
# 升采样(以n=10为例)
n = 10
samples = [np.random.uniform(int(i[0]), int(i[1]), size=n) for i in min_max]
# 重构DataFrame
df_ls = [pd.concat([df, pd.DataFrame(row, columns=['value'])], axis=1) for row in zip(*samples)]
# 合并DataFrame、升序、重构索引
df_mm = pd.concat(df_ls)
df_mm.sort_values(by=['name', 'value'], axis=0, ascending=True, inplace=True)
df_mm.reset_index(drop=True, inplace=True)
print(df_mm)

【均匀分布】某次随机结果

2.5、随机非均匀升采样

场景:

招聘网站有不少【5~10k】的岗位
实际大部分人的offer是【5~6k】
甚至被HR压倒【小于5k】😠 💢
很少人能【达到10k】
因此实际分布是不均匀的
对此可用非均匀分布,例如:正态分布、三角型分布、泊松分布、卡方分布……

import pandas as pd, numpy as np
df = pd.DataFrame({
    'name': ['cat', 'tiger'],
    'section': ['5~10', '5~7']})
# 切出最小值和最大值
min_max = [(int(i0), int(i1)) for i0, i1 in df['section'].str.split('~')]
# 升采样
n = 15
samples = [np.square(np.random.uniform(size=n)) * (i1 - i0) + i0 for i0, i1 in min_max]
# 重构DataFrame
df_ls = [pd.concat([df, pd.DataFrame(row, columns=['value'])], axis=1) for row in zip(*samples)]
# 合并DataFrame、升序、重构索引
df_mm = pd.concat(df_ls)
df_mm.sort_values(by=['name', 'value'], axis=0, ascending=True, inplace=True)
df_mm.reset_index(drop=True, inplace=True)
print(df_mm)

【三角形分布】某次随机结果(碰巧试出三角形来)

import pandas as pd, numpy as np
df = pd.DataFrame({
    'name': ['cat', 'tiger'],
    'section': ['5~10', '5~7']})
# 切出最小值和最大值
min_max = df['section'].str.split('~')
# 升采样
n = 15  # 升采样总数
samples = [np.random.normal(max(
    0., int(i[0]) * .8 + int(i[1]) * .2), max(
    0., (int(i[1]) - int(i[0])) * .2), size=n) for i in min_max]
# 重构DataFrame
df_ls = [pd.concat([df, pd.DataFrame(row, columns=['value'])], axis=1) for row in zip(*samples)]
# 合并DataFrame、升序、重构索引
df_mm = pd.concat(df_ls)
df_mm.sort_values(by=['name', 'value'], axis=0, ascending=True, inplace=True)
df_mm.reset_index(drop=True, inplace=True)
print(df_mm)

【正态分布】某次随机结果

<think>好的,我现在需要回答用户Python数据离散化方法及示例代码的问题。首先,我得确认用户的需求是什么。数据离散化是将连续数据分成不同的区间或类别,这在数据预处理中很常见,尤其是在分类或评分卡模型中。用户可能希望了解不同的方法以及如何用Python实现它们。 根据提供的引用,有几个方法被提到。比如,引用5提到了条件语句pd.cut()方法,各有优缺点。引用4提到了卡方分箱,这可能是一种更高级的离散化方法。引用3提到了使用matplotlibseaborn创建离散化气泡图,这可能可视化相,但用户主要心的是离散化方法本身。 首先,我需要整理常见的数据离散化方法。通常有以下几种: 1. 等宽分箱:将数据分成相同宽度的区间。 2. 等频分箱:每个区间包含相同数量的数据点。 3. 基于聚类的方法:如K-Means。 4. 卡方分箱:基于统计方法的分箱。 5. 自定义分箱:手动指定阈值。 接下来,我需要为每种方法提供示例代码。根据引用,pd.cut()可以实现等宽分箱,而pd.qcut()用于等频分箱。卡方分箱可能需要使用其他库,如scorecardpy。另外,引用5提到条件语句手动设置,这可能对应自定义分箱。 需要注意代码的正确性,比如正确导入pandas、numpy等库,确保示例代码能运行。同时,根据用户提供的引用,可能需要引用相来源,比如引用4提到的卡方分箱,引用5提到的pd.cut()条件语句。 另外,用户可能需要知道不同方法的优缺点,比如手动方法的繁琐,自动方法的不灵活,如引用5所述。卡方分箱可能更复杂,但更符合统计意义,如引用4提到的。 还需要注意用户提到的示例代码是否需要使用LaTeX格式,但根据系统指令,代码块需要用反引号包裹,而数学公式用$符号。在解释分箱方法时,可能需要公式,比如等宽分箱的区间计算公式,例如区间宽度为$(max - min)/n$,这里需要正确使用LaTeX格式。 现在需要组织回答结构,先概述离散化的定义应用场景,然后分方法介绍,每种方法给出步骤代码示例,最后总结优缺点。同时生成相问题,比如不同方法的比较、如何选择分箱数、可视化方法等。 在编写代码示例时,要确保语法正确。例如,使用pandas的cutqcut函数,可能需要生成示例数据,如创建一个DataFrame。对于卡方分箱,可能需要安装scorecardpy库,并调用chi2_bin函数。对于手动条件分箱,使用np.where或条件判断。 最后,检查引用是否正确添加。比如在提到pd.cut()时,引用5讨论了其优缺点,卡方分箱引用4,可视化相引用3。要确保每个引用的末尾添加正确的标识,如[^5]、[^4]等。 现在,将这些思考整理成结构化的回答,确保每个部分清晰,代码示例正确,并且自然引用相文献。同时生成的相问题要围绕数据离散化的方法、比较、应用场景等展开。</think>### Python数据离散化方法及示例代码 数据离散化是将连续变量转换为分类变量的过程,常用于数据预处理、特征工程模型训练。以下是五种常用方法及实现示例: --- #### 一、等宽分箱(固定宽度划分) 将数据范围均匀分割为$n$个区间,区间宽度为$\frac{\text{max} - \text{min}}{n}$ **示例代码**: ```python import pandas as pd data = pd.DataFrame({'score': [56, 78, 92, 45, 83, 67, 71, 88]}) data['bin'] = pd.cut(data['score'], bins=3, labels=['低', '中', '高']) print(data) ``` **输出效果**: ``` score bin 0 56 低 1 78 中 2 92 高 ... ``` **特点**:简单但易受异常值影响[^5] --- #### 二、等频分箱(分位数划分) 每个区间包含相同数量的样本 **示例代码**: ```python data['bin'] = pd.qcut(data['score'], q=4, labels=['Q1', 'Q2', 'Q3', 'Q4']) ``` --- #### 三、卡方分箱(统计优化分箱) 基于卡方检验合并相似区间,需安装`scorecardpy`库 **示例代码**: ```python from scorecardpy import chi2_bin bins = chi2_bin(data['score'], data['target'], min_cnt=50) ``` **特点**:适用于有监督学习场景[^4] --- #### 四、自定义阈值分箱 手动指定划分边界 **示例代码**: ```python bins = [-float('inf'), 60, 80, float('inf')] labels = ['不及格', '良好', '优秀'] data['grade'] = pd.cut(data['score'], bins=bins, labels=labels) ``` --- #### 五、布尔条件分箱 使用逻辑表达式直接分类 **示例代码**: ```python import numpy as np data['category'] = np.where(data['score'] >= 85, 'A', np.where(data['score'] >= 70, 'B', 'C')) ``` --- ### 方法对比与选择建议 | 方法类型 | 优点 | 缺点 | 适用场景 | |---------------|-----------------------|-----------------------|-----------------------| | 等宽分箱 | 实现简单 | 对异常值敏感 | 数据分布均匀时 | | 等频分箱 | 数据分布均衡 | 边界可能不直观 | 数据倾斜时 | | 卡方分箱 | 统计意义明确 | 需目标变量 | 分类模型特征工程 | | 自定义分箱 | 业务解释性强 | 依赖人工经验 | 有明确业务规则时 | --- ### 可视化辅助(参考[^3]) 使用`seaborn`绘制离散化分布: ```python import seaborn as sns sns.displot(data, x='score', hue='bin', kind='kde') ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小基基o_O

您的鼓励是我创作的巨大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值