数据导入与预处理-第6章-02数据变换

2 数据变换

主要是对数据进行规范化的操作,将数据转换成“适当的”格式,以适用于挖掘任务及算法的需要。

2.1 数据变换方法(6.2.1 )

数据变换的常见处理方式包括:

数据标准化处理
数据离散化处理
数据泛化处理

在对数据进行分析或挖掘之前,数据必须满足一定的条件:

比如方差分析时要求数据具有正态性方差齐性独立性无偏性,需进行诸如平方根对数平方根反正弦操作,实现从一种形式到另一种“适当”形式的变换,以适用于分析或挖掘的需求,这一过程就是数据变换。

数据变换主要是从数据中找到特征表示,通过一些转换方法减少有效变量的数目或找到数据的不变式,常见的操作可以分为数据标准化处理、数据离散化处理和数据泛化处理三类。

2.1.1 数据标准化处理

数据标准化处理是将数据按照一定的比例缩放,使之投射到一个比较小的特定区间。
最小-最大标准化(规范化)
最小-最大规范化:也称为离差标准化,是对原始数据的线性变换,使结果值映射到[0,1]之间。
转换函数如:
在这里插入图片描述
其中 max为样本数据的最大值,min为样本数据的最小值。max-min为极差。
以一个例子说明标准化的计算过程。
在这里插入图片描述

均值标准化(规范化)
零-均值规范化:也叫标准差标准化,经过处理的数据的平均数为0,标准差为1。转化函数为:
在这里插入图片描述
其中 x ‾ \overline{x} x为原始数据的均值, σ \sigma σ为原始数据的标准差。

小数定标标准化(规范化)
小数定标规范化:通过移动属性值的小数位数,将属性值映射到[-1,1]之间,移动的小数位数取决于属性值绝对值的最大值。转化函数为:移动数据的小数点,使数据映射到[-1,1]。
转换函数如下:
x ∗ = x 1 0 k x^{\ast }=\dfrac{x}{10^{k}} x=10kx

2.1.2 数据离散化处理

一些数据挖掘算法,特别是某些分类算法,要求数据是分类属性形式,如ID3算法、Apriori算法等。这样,常常需要将连续属性变换成分类属性,即连续属性离散化。
数据离散化处理一般是在数据的取值范围内设定若干个离散的划分点,将取值范围划分为若干离散化的区间,分别用不同的符号或整数值代表落在每个子区间的数值。
连续属性变换成分类属性涉及两个子任务:决定需要多少个分类变量,以及确定如何将连续属性值映射到这些分类值

等宽法
等宽法将属性的值域从最小值到最大值划分成具有相同宽度的区间,具体划分多少个区间由数据本身的特点决定,或者由具有业务经验的用户指定
等频法
等频法将相同数量的值划分到每个区间,保证每个区间的数量基本一致。
等宽法和等频法虽然简单,但是都需要人为地规定划分区间的个数。等宽法会不均匀地将属性值分到各个区间,导致有些区间包含较多数据,有些区间包含较少数据,不利于挖掘后期决策模型的建立。

2.1.3 数据泛化处理(分层)

数据泛化处理指用高层次概念取代低层次概念的数据。例如,年龄是一个低层次的概念,它经过泛化处理后会变成诸如青年、中年等高层次的概念。

本文介绍的Pandas中关于数据变换的基本操作包括轴向旋转(6.2.2小节)、分组与聚合(6.2.3小节)、哑变量处理(6.2.4小节)和面元划分(6.2.5小节)。

2.2 轴向旋转(6.2.2 )

掌握pivot()和melt()方法的用法,可以熟练地使用这些方法实现轴向旋转操作

2.2.1 pivot方法

pivot()方法用于将DataFrame类对象的某一列数据转换为列索引,也叫透视方法。官网中对pivot()函数的描述如下:

Reshape data (produce a “pivot” table) based on column values. Uses unique values from specified index / columns to form axes of the resulting DataFrame. This function does not support data aggregation, multiple values will result in a MultiIndex in the columns.
基于列值重塑数据(生成一个“透视”表)。使用来自指定索引/列的唯一值来形成结果DataFrame的轴。此函数不支持数据聚合,多个值将导致列中的MultiIndex。

pivot()函数如下:

DataFrame.pivot(index=None, columns=None, values=None)

index:表示新生成对象的行索引,若未指定说明使用现有对象的行索引。
columns:表示新生成对象的列索引。
values :表示填充新生成对象的值。

要想了解pivot()函数,可以先了解下pivot_table()函数。pivot_table()函数是pivot()函数的泛化,pivot_table函数允许值的聚合。
pivot_table透视的过程如下图:
在这里插入图片描述

假设某商店记录了5月和6月活动期间不同品牌手机的促销价格,保存到以日期、商品名称、价格为列标题的表格中,若对该表格的商品名称列进行轴向旋转操作,即将商品名称一列的唯一值变换成列索引,将出售日期一列的唯一值变换成行索引。
在这里插入图片描述
示例代码如下:

构建DataFrame:

import pandas as pd
df_obj =  pd.DataFrame({'商品名称': ['荣耀9X','小米6x','OPPO A1',
                                    '荣耀9X','小米6x','OPPO A1'],
                        '出售日期': ['5月25日', '5月25日','5月25日',
                                        '6月18日','6月18日', '6月18日'],
                          '价格(元)': [999, 1399, 1399, 800, 1200, 1250]})
df_obj

输出为:
在这里插入图片描述
将出售日期一列的唯一数据变换为行索引,商品一列的唯一数据变换为列索引:

# 将出售日期一列的唯一数据变换为行索引,商品一列的唯一数据变换为列索引
new_df = df_obj.pivot(index='出售日期', columns='商品名称',values='价格(元)')
new_df

输出为:
在这里插入图片描述

2.2.2 melt方法

melt()是pivot()的逆操作方法,用于将DataFrame类对象的列索引转换为一行数据。

DataFrame.melt(id_vars=None, value_vars=None, var_name=None, 
         value_name='value', col_level=None, ignore_index=True)

id_vars:表示无需被转换的列索引。
value_vars:表示待转换的列索引,若剩余列都需要转换,则忽略此参数。
var_name:表示自定义的列索引。
value_name:表示自定义的数据所在列的索引。
ignore_index:表示是否忽略索引,默认为True。

示例代码如下:
查看初始数据

new_df

输出为:
在这里插入图片描述
# 将列索引转换为一行数据:

# 将列索引转换为一行数据
new_df.melt(value_name='价格(元)', ignore_index=False)

输出为:
在这里插入图片描述

2.3 分组与聚合(6.2.3 )

分组与聚合是常见的数据变换操作

分组指根据分组条件(一个或多个键)将原数据拆分为若干个组;
聚合指任何能从分组数据生成标量值的变换过程,这一过程中主要对各分组应用同一操作,并把操作后所得的结果整合到一起,生成一组新数据。

在这里插入图片描述

下面通过一个例子说明分组聚合的过程:
在这里插入图片描述

掌握分组与聚合的过程,可以熟练地groupby()、agg()、transfrom()和apply()方法实现分组与聚合操作

2.3.1 分组操作groupby()

2.3.1.1 分组操作

pandas中使用groupby()方法根据键将原数据拆分为若干个分组。

groupby(by=None, axis=0, level=None, as_index=True, sort=True, 
        group_keys=True, squeeze=<object object>, observed=False, dropna=True)

by:表示分组的条件,可以取值为字符串、列表、字典或Series、函数等。
axis:表示分组操作的轴编号,可以是0或1。该参数的默认值为0,代表沿列方向操作。
level:表示标签索引所在的级别,默认为None。
as_index:表示聚合后新数据的索引是否为分组标签的索引,默认为True。
sort:表示是否对分组索引进行排序,默认为True。
group_keys:表示是否显示分组标签的名称,默认为True。

使用pandas的groupby()方法拆分数据后会返回一个GroupBy类的对象,该对象是一个可迭代对象,它里面包含了每个分组的具体信息,但无法直接被显示。
DataFrameGroupBy和SeriesGroupBy都是GroupBy的子类。
若DataFrame类对象调用groupby()方法,会返回一个DataFrameGroupBy类的对象。
若Series类对象调用groupby()方法,会返回一个SeriesGroupBy类的对象。

分组操作案例:
分组初始化

# 分组初始化
import pandas as pd
df_obj = pd.DataFrame({"key":["C", "B", "C", "A", "B", "B", "A", "C", "A"], 
                       "data":[2, 4, 6, 8, 10, 1, 3, 5, 7]})
# 根据key列对df_obj进行分组
groupby_obj = df_obj.groupby(by="key")
groupby_obj

输出为:

在这里插入图片描述GroupBy对象不可查看,可以遍历过去其中数据
遍历DataFrameGroupBy类的对象:

# 遍历DataFrameGroupBy类的对象
for group in groupby_obj:  
    print(group)
    print("-"*10)

输出为:
在这里插入图片描述
通过列表生成器 获取DataFrameGroupBy的数据:

# 通过列表生成器 获取DataFrameGroupBy的数据
result = dict([x for x in groupby_obj])['A'] # 字典中包含多个DataFrame
result

输出为:
在这里插入图片描述
通过groups获取内容

# 查看全部分组内容
df_obj.groupby(["key"]).groups

输出为:
在这里插入图片描述
查看指定分组内容

# 查看指定分组内容
df_obj.groupby(["key"]).get_group(("A"))

输出为:
在这里插入图片描述

2.3.1.2 分组+内置聚合

分组+自定义聚合:

# 分组+自定义聚合
import pandas as pd
df_obj = pd.DataFrame({"key":["C", "B", "C", "A", "B", "B", "A", "C", "A"], 
                       "data":[2, 4, 6, 8, 10, 1, 3, 5, 7]})
print(df_obj)
df_obj[['key','data']].groupby(by="key").max()

输出为:
在这里插入图片描述
分组+内置聚合,取消分组键做索引

# 取消索引 按照上一题要求进行分组,但不使用 key 做为索引
df_obj[['key','data']].groupby(by="key", as_index=False).max()

输出为:
在这里插入图片描述
分组+内置函数+排序

# 排序  分组 聚合后 排序
df_obj[['key','data']].groupby(by="key").max().sort_values('data',ascending=False)

输出为:
在这里插入图片描述
分组+内置函数+频率统计

# 频率 计算不同key,不同data出现的次数
pd.DataFrame(df_obj.groupby("key")['data'].value_counts())

输出为:
在这里插入图片描述

2.3.2 聚合操作 (6.2.3 )

pandas中可通过多种方式实现聚合操作,除前面介绍过的内置统计方法之外,还包括agg()、transfrom()和apply()方法。
初始化聚合所需的DF:

# 初始化分组DF
import pandas as pd
df_obj = pd.DataFrame({'a': [0, 6, 12, 18, 24, 30],
                       'b': [1, 7, 13, 19, 25, 31],
                       'c': [1, 8, 14, 20, 26, 32],
                       'd': [2, 9, 15, 21, 27, 33],
                       'e': [2, 10, 16, 22, 28, 34],
                       'f': [2, 2, 2, 3, 3, 2]})
df_obj

输出为:
在这里插入图片描述查看DF的值:

# 根据列表对df_obj进行分组,列表中相同元素对应的行会归为一组
groupby_obj = df_obj.groupby(by=['A', 'A', 'B', 'B', 'A', 'B'])
# groupby_obj.groups
print(dict([x for x in groupby_obj]))
print('-'*10)

for (key,value) in dict([x for x in groupby_obj]).items():
    print(key)
    print(value)

输出为:
在这里插入图片描述

2.3.2.1 agg()方法

agg()方法既接收内置统计方法,又接收自定义函数,甚至可以同时运用多个方法或函数,或给各列分配不同的方法或函数,能够对分组应用灵活的聚合操作。

传入自定义函数:

for (key,value) in dict([x for x in groupby_obj]).items():
    print(key)
    print(value)
# 定义求极差的函数
def my_range(arr):
    return arr.max()-arr.min()
groupby_obj.agg(my_range)  # 使用agg()方法聚合分组数据

输出为:
在这里插入图片描述
指定列聚合

# 使用agg()方法聚合分组中指定列的数据
groupby_obj.agg({'a':'max', 'c':'sum', 'e': my_range})

输出为:
在这里插入图片描述

在使用agg方法中,还经常使用重置索引+重命名的方式:

# 初始化分组DF
import pandas as pd
df_obj = pd.DataFrame({'a': [0, 1, 2, 3, 4, 5],
                       'b': [1, 7, 13, 19, 25, 31],
                       'c': [1, 8, 14, 20, 26, 32],
                       'd': [2, 9, 15, 21, 27, 33],
                       'e': [2, 10, 16, 22, 28, 34],
                       'f': [2, 2, 2, 3, 3, 2]})
print(df_obj)

df_obj.groupby(by='f').agg({'a':'count'})

输出为:
在这里插入图片描述

会发现,经过agg聚合后,分组键做了索引,聚合之后的a列的列名为a,这个列名会与原有的列名冲突,换成a_count比较合适,方法如下:

df_obj.groupby(by='f').agg({'a':'count'}).reset_index().rename(columns={'a': 'a_count'})

输出为:
在这里插入图片描述

2.3.2.2 transfrom()方法

transfrom()方法能对分组应用灵活的运算操作,同时可使聚合前与聚合后的数据结构保持一致。

初始化DF

# 初始化分组DF
import pandas as pd
df_obj = pd.DataFrame({'a': [0, 6, 12, 18, 24, 30],
                       'b': [1, 7, 13, 19, 25, 31],
                       'c': [1, 8, 14, 20, 26, 32],
                       'd': [2, 9, 15, 21, 27, 33],
                       'e': [2, 10, 16, 22, 28, 34],
                       'f': [2, 2, 2, 3, 3, 2]})
df_obj

输出为:
在这里插入图片描述

基于transform求最大值:

df_obj['a_max'] = df_obj[['a','f']].groupby(by=['f']).transform('max')
df_obj

输出为:
在这里插入图片描述
如果不提前选取列,会生成同等结果的返回结果:

del df_obj['a_max']
df_obj.groupby(by=['f']).transform('max')

输出如下:
在这里插入图片描述

2.3.2.3 apply()方法

apply()方法既能直接接收内置方法,又可以接收自定义的函数。
与前几种聚合方式相比,使用apply()方法聚合数据的操作更灵活,它可以代替前两种聚合完成基础操作,另外也可以解决一些特殊聚合操作。

apply(func, *args, **kwargs)

func:表示应用于各分组的函数或方法。
*args和**kwargs :表示传递给func的位置参数或关键字参数。

案例如下:

# 初始化分组DF
import pandas as pd
df_obj = pd.DataFrame({'a': [0, 6, 12, 18, 24, 30],
                       'b': [1, 7, 13, 19, 25, 31],
                       'c': [1, 8, 14, 20, 26, 32],
                       'd': [2, 9, 15, 21, 27, 33],
                       'e': [2, 10, 16, 22, 28, 34],
                       'f': [2, 2, 2, 3, 3, 2]})
print(df_obj)
# 自定义函数,用于计算每个数据除以10的余数
def div_hun(df):
    return df.iloc[:, :] % 10
df_obj.groupby(by=['f']).apply(div_hun)

输出为:
在这里插入图片描述

2.3.2.4 filter()方法

通过filter也可过滤分组后的数据:

# 初始化分组DF
import pandas as pd
df_obj = pd.DataFrame({'a': [0, 6, 12, 18, 24, 30],
                       'b': [1, 7, 13, 19, 25, 31],
                       'c': [1, 8, 14, 20, 26, 32],
                       'd': [2, 9, 15, 21, 27, 33],
                       'e': [2, 10, 16, 22, 28, 34],
                       'f': [2, 2, 2, 3, 3, 2]})

print(df_obj)
df_obj.groupby('f').filter(lambda x: x['a'].max() >26)

输出为:
在这里插入图片描述

2.4 哑变量处理(6.2.4 )

在数据分析或挖掘中,一些算法模型要求输入以数值类型表示的特征,但代表特征的数据不一定都是数值类型的,其中一部分是类别型的,例如,受教育程度表示方式有大学、研究生、博士等类别,这些类别均为非数值类型的数据。为了将类别类型的数据转换为数值类型的数据,类别类型的数据在被应用之前需要经过“量化”处理,从而转换为哑变量。

什么是哑变量
哑变量又称虚拟变量、名义变量等,它是人为虚设的变量,用来反映某个变量的不同类别,常用的取值为0和1。需要说明的是,0和1并不代表数量的多少,而代表不同的类别。
假设变量“职业”有司机、学生、导游、工人、教师共5个类别,这5个类别分别有0和1两种取值,0代表非此种类别,1代表此种类别。

实现哑变量的方法:
pandas中使用get_dummies()函数对类别数据进行哑变量处理,并在处理后返回一个哑变量矩阵。

get_dummies(data, prefix=None, prefix_sep='_', dummy_na=False,
        columns=None, sparse=False, drop_first=False, dtype=None)

data:表示待处理的类别数据,可以是数组、DataFrame类或Series类对象。
prefix:表示列索引名称的前缀,默认为None。
prefix_sep:表示附加前缀的分隔符,默认为“_”。
columns:表示哑变量处理的列索引名称,默认为None。

初始化数据:

# 初始化DF
import pandas as pd
position_df = pd.DataFrame({'职业': ['工人', '学生', '司机', '教师', '导游']})
position_df

输出为:
在这里插入图片描述

哑变量处理, 并给哑变量添加前缀:

# 哑变量处理, 并给哑变量添加前缀
result = pd.get_dummies(position_df, prefix=['col'])  
result

输出为:
在这里插入图片描述

2.5 面元划分(6.2.5 )

掌握cut()函数的用法,可以熟练地使用过该函数实现面元划分操作
面元划分是指数据被离散化处理,按一定的映射关系划分为相应的面元(可以理解为区间),只适用于连续数据。连续数据又称连续变量,指在一定区间内可以任意取值的数据,该类型数据的特点是数值连续不断,相邻两个数值可作无限分割。

pandas中使用cut()函数能够实现面元划分操作,cut()函数会采用等宽法对连续型数据进行离散化处理。

cut(x, bins, right=True, labels=None, retbins=False, precision=3, 
      include_lowest=False, duplicates='raise', ordered=True)

x:表示面元划分的连续数据,可以取值为一维数组或Series类对象。
bins:表示划分面元的依据。
right:表示右端点是否为闭区间,默认为True。
precision:表示区间标签的精度,默认为3。
include_lowest:表示是否包含区间的左端点,默认为False。

cut()函数会返回一个Categorical类对象,该对象可以被看作一个包含若干个面元名称的数组,通过categories属性可以获取所有的分类,即每个数据对应的面元。

在这里插入图片描述

案例如下:

import pandas as pd
ages = pd.Series([19, 21, 25, 55, 30, 45, 52, 46, 20])
bins = [0, 18, 30, 40, 50, 100]
# 使用cut函数划分年龄区间
cuts = pd.cut(ages, bins)
cuts

输出为:
在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

IT从业者张某某

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

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

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

打赏作者

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

抵扣说明:

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

余额充值