数据清洗第2篇章 - 数据转换处理

数据清洗是数据分析过程中至关重要的一步,它确保数据的准确性、一致性和完整性。这不仅有助于提高分析结果的可靠性和有效性,还能为算法建模决策提供高质量的数据基础。在进行数据分析和建模的过程中,大量的时间花在数据准备上:加载、清理、转换和重新排列,这样的工作占用了工程师 80% 以上的时间。所以掌握常用的数据清洗方法,将帮助我们能更高效、更高质量完成数据清洗工作。

我们将从易到难来讲述数据清洗系列三篇章,本文为第二篇章:数据转换处理,包括数据映射、数据替换、数据离散化、数据标准化、数据归一化,我们将理论和实践结合,层层递进一步一步掌握缺数据转换的处理方法。

1、数据映射

在对数据进行清洗时,我们经常需要将数据进行分类,例如根据年龄划分为儿童/青年/中年/老年,根据分数划分为不及格/及格/良好/优秀等。在 pandas 中,我们可以使用 map 方法用于对 DataFrame 中的元素进行映射。如下所示,我们使用字典进行配置映射,我们根据姓名-性别配置表,基于 name 映射出 sex 列

import pandas as pd

frame_data = pd.DataFrame({'name': ['tom','paz','leo','tom','leo'],
                           'age': [11, 10, 10, 11, 12]})

# 创建映射字典
mapping = {'tom':'男', 'paz':'女', 'leo':'男'}
# 使用 map 进行替换
frame_data['sex'] = frame_data['name'].map(mapping)
frame_data

# ----输出----
  name age sex
0  tom  11  男
1  paz  10  女
2  leo  10  男
3  tom  11  男
4  leo  12  男

当被映射的属性比较多时,单纯的配置表就无法满足我们的需求了。此时,我们可以使用函数进行转换,如下所示,配置表变成映射函数,函数中编写相应的映射逻辑

import pandas as pd

frame_data = pd.DataFrame({'name': ['tom','paz','leo','tom','leo'],
                           'height': [112, 100, 120, 101, 122]})

# 定义一个简单的映射函数
def height_type(height):
    if height >= 120:
        return 'high'
    elif height < 110:
        return 'low'
    else:
        return 'middle'

# 使用 map 进行替换
frame_data['type'] = frame_data['height'].map(height_type)
frame_data

# ----输出----
    name height  type
0  tom  112  middle
1  paz  100  low
2  leo  120  high
3  tom  101  low
4  leo  122  high
2、数据替换

在数据预处理中,我们有时候要对数据进行替换处理。此时,我们可以使用 replace 方法用于替换 DataFrame 或 Series 中的特定值。它可以用于替换单个值、列表、字典或使用正则表达式进行复杂的替换。我们可以进行进行简单的单个值替换,如下所示

import pandas as pd

frame_data = pd.DataFrame({'name': ['tom','paz','leo','tom','leo'],
                           'age': [1, 10, 10, 1, 12]})
# 将 1 替换为 11
frame_data.replace(1, 11)

# ----输出----
    name age
0  tom  11
1  paz  10
2  leo  10
3  tom  11
4  leo  12

当然我们还可以使用字典配置来进行多行多列的替换

import pandas as pd

frame_data = pd.DataFrame({'name': ['tom','paz','leo','tom','leo'],
                           'age': [1, 10, 10, 1, 12]})
# 将paz替换为jim,将1替换为11
frame_data.replace({'name': {'paz':'jim'}, 'age': {1:11}})

# ----输出----
  name age
0  tom  11
1  jim  10
2  leo  10
3  tom  11
4  leo  12

如果有更复杂的替换场景,我们还可以使用正则表达式进行替换

import pandas as pd

frame_data = pd.DataFrame({'name': ['tom','paz','leo','tom','leo'],
                           'age': [1, 10, 10, 1, 12]})
# 使用正则表达式替换
frame_data.replace(to_replace=r'^t', value='T', regex=True)

# ----输出----
    name age
0  Tom  1
1  paz  10
2  leo  10
3  Tom  1
4  leo  12

replace 替换默认都是生成一个新的数据,我们如果想直接在原 DataFrame 上进行替换,可以设置 inplace=True 

frame_data.replace(1, 10, inplace=True)
3、数据离散化

在数据预处理中连续值经常需要离散化(也叫分箱)进行分析,在 pandas 中可以使用 cut 进行数据的切分成组

import pandas as pd

series_data = pd.Series([10, 20, 30, 40, 50, 60, 70, 80, 90])
# 定义区间边界
bins = [0, 20, 50, 80, 100]
# 应用cut函数
categories = pd.cut(series_data, bins)
categories

# ----输出----
0      (0, 20]
1      (0, 20]
2     (20, 50]
3     (20, 50]
4     (20, 50]
5     (50, 80]
6     (50, 80]
7     (50, 80]
8    (80, 100]
dtype: category
Categories (4, interval[int64, right]): [(0, 20] < (20, 50] < (50, 80] < (80, 100]]

可以看到 pandas 返回的对象是一个特殊的 Categorical 对象,其值为由 pandas.cut 计算出的箱,并且内部包含一个 categories(类别)数组。从结果中可以看到,区间的左边是小括号、右边是中括号,其与数学中的区间符号表示含义一致,小括号表示边是开放的,中括号表示它是封闭的(包括边)。我们可以通过传递 right=False 来改变哪一边是封闭的

pd.cut(series_data, bins, right=False)

# ----输出----
0      [0, 20)
1     [20, 50)
2     [20, 50)
3     [20, 50)
4     [50, 80)
5     [50, 80)
6     [50, 80)
7    [80, 100)
8    [80, 100)
dtype: category
Categories (4, interval[int64, left]): [[0, 20) < [20, 50) < [50, 80) < [80, 100)]

如果我们向语义化显示集合,可以通过向 labels 选项传递一个列表或数组来传入自定义的箱名也进行语义化显示

# 定义箱名
age_groups = ['young', 'middle', 'senior', 'old']
pd.cut(series_data, bins, labels=age_groups)

# ----输出----
0     young
1     young
2    middle
3    middle
4    middle
5    senior
6    senior
7    senior
8       old
dtype: category
Categories (4, object): ['young' < 'middle' < 'senior' < 'old']

将数据分箱后,我们经常需要统计相关分箱的数量。此时,我们可以通过 value_counts 方法统计每个箱子中的数量,其默认是按数量从多到少进行

categories.value_counts()

# ----输出----
(20, 50]     3
(50, 80]     3
(0, 20]      2
(80, 100]    1
Name: count, dtype: int64

其默认是按数量从多到少进行排序的,如果我们不想进行排序,而是直接按箱子的顺序进行输出,则可以通过设置属性 sort=False 不进行排序

categories.value_counts(sort=False)

# ----输出----
(0, 20]      2
(20, 50]     3
(50, 80]     3
(80, 100]    1
Name: count, dtype: int64

如果我们想等量划分每个箱子中的数量,可以在 cut 方法中传入整数(表示箱子数量)来代替显式的箱边,pandas 将根据数据中的最小值和最大值计算出等长的箱

pd.cut(series_data, 4)

# ----输出----
0    (9.92, 30.0]
1    (9.92, 30.0]
2    (9.92, 30.0]
3    (30.0, 50.0]
4    (30.0, 50.0]
5    (50.0, 70.0]
6    (50.0, 70.0]
7    (70.0, 90.0]
8    (70.0, 90.0]
dtype: category
Categories (4, interval[float64, right]): [(9.92, 30.0] < (30.0, 50.0] < (50.0, 70.0]

以上介绍了 cut 常用的特性,如果我们想通过样本分位数进行分箱,这时我们就需要使用 qcut 方法,通过定义每个分箱数量的占比,自动进行分箱边界值的划分,如下所示

import pandas as pd

series_data = pd.Series([10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
pd.qcut(series_data, [0, 0.2, 0.5, 0.9, 1])

# ----输出----
0    (9.999, 28.0]
1    (9.999, 28.0]
2     (28.0, 55.0]
3     (28.0, 55.0]
4     (28.0, 55.0]
5     (55.0, 91.0]
6     (55.0, 91.0]
7     (55.0, 91.0]
8     (55.0, 91.0]
9    (91.0, 100.0]
dtype: category
Categories (4, interval[float64, right]): [(9.999, 28.0] < (28.0, 55.0] < (55.0, 91.0] < (91.0, 100.0]]
4、数据标准化

在数据预处理中,标准化是常用的技术,标准化是将数据转换为均值为0、标准差为1的分布,常用于需要满足正态分布假设的算法中。

import pandas as pd

data = {'value': [10, 20, 30, 40, 50]}
df = pd.DataFrame(data)
# 计算均值和标准差
mean = df['value'].mean()
std = df['value'].std()
# 计算标准化,应用公式 ((x - mean) / std)
df['standardized'] = (df['value'] - mean) / std
df

# ----输出----
  value  standardized
0  10  -1.264911
1  20  -0.632456
2  30  0.000000
3  40  0.632456
4  50  1.264911
5、数据归一化

在数据预处理中,归一化是常用的技术,归一化是将数据缩放到一个特定的范围(通常是0到1)。适用于特征值范围差异较大的情况

import pandas as pd
data = {'value': [10, 20, 30, 40, 50]}
df = pd.DataFrame(data)
# 计算最小值和最大值
min_value = df['value'].min()
max_value = df['value'].max()
# 归一化计算,应用公式 ((x - min) / (max - min))
df['normalized'] = (df['value'] - min_value) / (max_value - min_value)
df

# ----输出----

    value normalized
0  10  0.00
1  20  0.25
2  30  0.50
3  40  0.75
4  50  1.00

本文,我们详细介绍了在数据清洗中我们可以如何进行数据转换,包括数据映射、数据替换、数据离散化、数据标准化、数据归一化,希望对阅读本文的读者有一定的学习提升和借鉴启发,不足之处也欢迎留言指出。

如果你喜欢本文,欢迎点赞,并且关注我们的微信公众号:Python数据挖掘分析,我们会持续更新数据挖掘分析领域的好文章,让大家在数据挖掘分析领域持续精进提升,成为更好的自己!

同时可以扫描以下二维码,加入 Python数据挖掘分析 群,在群内与众多业界大牛互动,了解行业发展前沿~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

coder_风逝

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值