规约1"/>
第6章 数据集成、变换与规约1
目录
- 6. 1 数据集成
- 6.1.1 数据集成概述
- 6.1.2 合并数据
- 6.1.2.1 pandas中用于合并数据的函数与方法
- 6.1.2.2 主键合并
- 6.1.2.2.1 pd.merger()
- 6.1.2.2.2 pd.merge_ordered()
- 6.1.2.2.3 pd.merge_asof()
- 6.1.2.3 堆叠合并数据
- 6.1.2.3.0 构建数据
- 6.1.2.3.1 pd.concat()
- 6.1.2.3.2 dataframe.join()
- 6.1.2.3.3 dataframe.append()
- 6.1.2.4 重叠合并数据
- 6.1.2.4.1 dfbine()
- 6.1.2.4.2 dfbine_first()
- 6.1.2.5 数据合并应用案例
- 6.1.2.5.1 读取数据并查看基本信息
- 6.1.2.5.2 处理缺失值
- 6.1.2.5.3 合并"student”表与“student_course"表
- 6.1.2.5.4 合并"student”表与“student_course"表合并的结果与“course”表
- 6.2 数据变换
- 6.2.1 数据变换概述
- 6.2.1.1 数据标准化处理
- 6.2.1.2 数据离散化处理
- 6.2.1.3 数据泛化处理
- 6.2.1.4 Pandas中有关数据变换的基本操作
- 6.2.2 Pandas 数据标准化处理操作
- 6.2.2.1 最小-最大标准化(Min-Max Normalization)
- 6.2.2.2 均值标准化(Z-Score Normalization)
- 6.2.2.3 小数定标标准化
- 6.2.3 Pandas数据离散化处理操作
- 6.2.3.1 时间数据的离散化
- 6.2.3.2 连续数据的离散化
- 6.2.3.2.1 距离区间法:自定义分箱区间实现离散化
- 6.2.3.2.2 频率区间法:按照等频率或指定频率离散化
- 6.2.3.2.3 聚类法实现离散化
- 6.2.4 Pandas数据泛化处理操作
- 6.2.5 Pandas数据变换的其他基本操作
- 6.2.5.1 Pandas轴向旋转
- 6.2.5.1.1 pivot()方法
- 6.2.5.1.2 melt()方法
- 6.2.5.2 Pandas分组与聚合
- 6.2.5.2.1 分组操作
- 6.2.5.2.2 聚合操作
- 6.2.5.3 Pandas哑变量处理
- 6.2.5.4 Pandas面元划分
- 6.2.5.1 Pandas轴向旋转
- 6.2.1 数据变换概述
- 6.3 数据规约
- 6.3.1 数据规约概述
- 6.3.2 重塑分层索引
- 6.3.3 降采样
- 6.4 案例——中国篮球运动员的基本信息分析
本博客所涉及的jupyter notebook及数据资料请在百度网盘下载
6. 1 数据集成
6.1.1 数据集成概述
数据分析中需要的数据往往来自不同的途径,这些数据的格式、特点、质量千差万别,给数据分析或挖掘增加了难度。为提高数据分析的效率,多个数据源的数据需要合并到一个数据源,形成一致的数据存储,这一过程就是数据集成。
在数据集成期间可能会面临很多问题,包括实体识别、冗余属性识别、元组重复、数据值冲突等问题!
-
实体识别:
实体识别指从不同数据源中识别出现实世界的实体,主要用于统一不同数据源的矛盾之处,常见的矛盾包括同名异义、异名同义、单位不统一等! -
冗余属性识别:
冗余属性是数据集成期间极易产生的问题,这一问题主要是因为同一属性多次出现、同一属性命名方式不一致造成的。 -
元组重复:
元组重复是数据集成期间另一个容易产生的数据冗余问题,这一问题主要是因为录入错误或未及时更新造成的。
由于存在如上问题,数据集成之后可能需要经过数据清理,以便清除可能存在的实体识别、冗余属性识别和元组重复问题。
pandas中有关数据集成的操作是合并数据,并为该操作提供了丰富的函数或方法。
6.1.2 合并数据
6.1.2.1 pandas中用于合并数据的函数与方法
pandas中内置了许多能轻松地合并数据的函数与方法,通过这些函数与方法可以将Series类对象或DataFrame类对象进行符合各种逻辑关系的合并操作,合并后生成一个整合的Series或DataFrame类对象。
6.1.2.2 主键合并
主键合并数据类似于关系型数据库的连接操作,主要通过指定一个或多个键将两组数据进行连接,通常以两组数据中重复的列索引为合并键。
6.1.2.2.1 pd.merger()
- pd.merge()的语法格式:
pd.merge(left, # 待合并的2个数据框 right, how='inner', # ‘left’, ‘right’, ‘outer’, ‘inner’, ‘cross’ on=None, # 连接的键,默认是相同的键 left_on=None, # 指定不同的连接字段:键不同,但是键的取值有相同的内容 right_on=None, left_index=False, # 根据索引来连接 right_index=False, sort=False, # 是否排序 suffixes=('_x', '_y'), # 改变后缀 copy=True, indicator=False, # 显示字段来源 validate=None)
-
参数的具体解释为:
-
left、right:表示参与合并的Series类对象或DataFrame类对象
-
how:数据合并的方式,有5种:{‘left’, ‘right’, ‘outer’, ‘inner’, ‘cross’}, 默认是 ‘inner’
-
1、left:左连接,保留left的全部数据,类比于SQL的left join;
-
2、right:右连接,保留right的全部数据,类比于SQL的right join
-
3、outer:全连接功能,left与right的数据都将被保留,类似SQL的full outer join
-
4、inner:基于left合right的共有键的交叉连接,类比于SQL的inner join
-
5、cross:创建两个数据帧DataFrame的笛卡尔积,默认保留左边的顺序
-
-
on:连接的列属性;默认是两个DataFrame的相同字段
-
left_on/right_on:指定两个不同的键进行联结
-
left_index、right_index:通过索引进行合并
-
suffixes:指定我们自己想要的后缀
-
indictor:显示字段的来源
-
-
pd.merge()实例:
# 模拟数据
import pandas as pd
df_left = pd.DataFrame({'key':['K0','K1','K2','K4'],'A':['A0','A1','A2','A3'],'B':['B0','B1','B2','B3']})
df_right = pd.DataFrame({'key':['K0','K1','K2','K3'],'C':['C0','C1','C2','C3'],'D':['D0','D1','D2','D3']})
df_left
key | A | B | |
---|---|---|---|
0 | K0 | A0 | B0 |
1 | K1 | A1 | B1 |
2 | K2 | A2 | B2 |
3 | K4 | A3 | B3 |
df_right
key | C | D | |
---|---|---|---|
0 | K0 | C0 | D0 |
1 | K1 | C1 | D1 |
2 | K2 | C2 | D2 |
3 | K3 | C3 | D3 |
1. 内连接----共有键部分的连接
# 以key为主键,采用内连接的方式合并数据
result = pd.merge(df_left, df_right, on='key',how='inner')
result
key | A | B | C | D | |
---|---|---|---|---|---|
0 | K0 | A0 | B0 | C0 | D0 |
1 | K1 | A1 | B1 | C1 | D1 |
2 | K2 | A2 | B2 | C2 | D2 |
图解过程如下:
- 两个数据框df_left、df_right有相同的字段key
- 默认是通过相同的字段(键)进行关联,取出键中相同的值(K0,K1,K2),若每个键的记录要全部显示
# 默认参数情况下的连接及为内连接
result = pd.merge(df_left,df_right)
result
key | A | B | C | D | |
---|---|---|---|---|---|
0 | K0 | A0 | B0 | C0 | D0 |
1 | K1 | A1 | B1 | C1 | D1 |
2 | K2 | A2 | B2 | C2 | D2 |
# 也可以采用dataFrame对象的方法的方式调用
df_left.merge(df_right)
key | A | B | C | D | |
---|---|---|---|---|---|
0 | K0 | A0 | B0 | C0 | D0 |
1 | K1 | A1 | B1 | C1 | D1 |
2 | K2 | A2 | B2 | C2 | D2 |
2. 左外连接----以左数据为主,保留左侧全部的连接
# 以key为主键,采用左外连接的方式合并数据
result = pd.merge(df_left, df_right, on='key', how='left')
result
key | A | B | C | D | |
---|---|---|---|---|---|
0 | K0 | A0 | B0 | C0 | D0 |
1 | K1 | A1 | B1 | C1 | D1 |
2 | K2 | A2 | B2 | C2 | D2 |
3 | K4 | A3 | B3 | NaN | NaN |
# 类似的
result = df_left.merge(df_right,on='key',how='left')
result
key | A | B | C | D | |
---|---|---|---|---|---|
0 | K0 | A0 | B0 | C0 | D0 |
1 | K1 | A1 | B1 | C1 | D1 |
2 | K2 | A2 | B2 | C2 | D2 |
3 | K4 | A3 | B3 | NaN | NaN |
图解过程如下:
- 以左边数据框中的键(K0,K1,K2,K4)为基准;
- 如果左边存在(K4)但是右边不存在(K4),则右边用NaN表示
3. 右外连接----以右数据为主,保留右侧全部的连接
# 以key为主键,采用右外连接的方式合并数据
result = pd.merge(df_left, df_right, on='key', how='right')
result
key | A | B | C | D | |
---|---|---|---|---|---|
0 | K0 | A0 | B0 | C0 | D0 |
1 | K1 | A1 | B1 | C1 | D1 |
2 | K2 | A2 | B2 | C2 | D2 |
3 | K3 | NaN | NaN | C3 | D3 |
图解过程如下:
- 以右边数据框中的键(K0,K1,K2,K3)为基准;
- 如果右边存在(K3)但是右边不存在(K3),则左边用NaN表示
4. 全外连接----左右两侧数据都完全保留的连接
# 以key为主键,采用全外连接的方式合并数据
result = pd.merge(df_left, df_right, on='key', how='outer')
result
key | A | B | C | D | |
---|---|---|---|---|---|
0 | K0 | A0 | B0 | C0 | D0 |
1 | K1 | A1 | B1 | C1 | D1 |
2 | K2 | A2 | B2 | C2 | D2 |
3 | K4 | A3 | B3 | NaN | NaN |
4 | K3 | NaN | NaN | C3 | D3 |
图解过程如下:
outer称之为外连接,在拼接的过程中会取两个数据框中键的并集进行拼接
- 外连接,取出全部交集键的并集。例子中是user的并集
- 如果某个键在某个数据框中不存在数据,则为NaN
5. 笛卡尔积----两个数据框中的数据交叉匹配,出现n1*n2的数据量
# 以key为主键,采用笛卡尔积连接的方式合并数据
result = pd.merge(df_left, df_right, how='cross')
print(result)
key_x A B key_y C D
0 K0 A0 B0 K0 C0 D0
1 K0 A0 B0 K1 C1 D1
2 K0 A0 B0 K2 C2 D2
3 K0 A0 B0 K3 C3 D3
4 K1 A1 B1 K0 C0 D0
5 K1 A1 B1 K1 C1 D1
6 K1 A1 B1 K2 C2 D2
7 K1 A1 B1 K3 C3 D3
8 K2 A2 B2 K0 C0 D0
9 K2 A2 B2 K1 C1 D1
10 K2 A2 B2 K2 C2 D2
11 K2 A2 B2 K3 C3 D3
12 K4 A3 B3 K0 C0 D0
13 K4 A3 B3 K1 C1 D1
14 K4 A3 B3 K2 C2 D2
15 K4 A3 B3 K3 C3 D3
笛卡尔积的图解过程如下:
- 出现的数据量是4*2,userid下面的数据交叉匹配
- 在最终结果中相同的字段userid为了避免混淆,会带上默认的后缀_x、_y
6.1.2.2.2 pd.merge_ordered()
使用可选的填充/插值对有序数据执行合并。专为时间序列数据等有序数据而设计。
- pd.merge_ordered()语法格式:
pandas.merge_ordered(left, right, on=None, left_on=None, right_on=None, left_by=None, right_by=None, fill_method=None, suffixes=('_x', '_y'), how='outer')
-
参数解释:
-
left: 用于连接的 左DataFrame
-
right: 用于连接的 右DataFrame
-
on: 连接关键字。必须 同时存在于 左DataFrame、右DataFrame
-
left_on: 左DataFrame 中用于连接的关键字
-
right_on: 右DataFrame 中用于连接的关键字
-
left_by: 对 左DataFrame 进行分组的关键字
-
right_by: 对 右DataFrame 进行分组的关键字
-
fill_method: 对缺失数据填充的值
-
suffixes: 连接后,同时存在于 左DataFrame、右DataFrame 中的字段,添加的后缀名
-
how: 连接方式。默认为 外连接
-
-
注意:
-
使用参数 on 时,不能同时使用 “left_on” 或 “right_on”
-
left_on 与 right_on 必须同时存在
-
如果 on、left_on 、right_on 的参数值均为空时,默认以 同时存在于两个 DataFrame 中的列,为连接关键字。
如果不存在共同列,将会报错:pandas.errors.MergeError: No common columns to perform merge on. -
left_by 与 right_by 不能同时存在
-
pd.merge_ordered()实例:
- 构建实例数据
df1 = pd.DataFrame({"key": ["a", "c", "e", "a", "c", "e"],"lvalue": [1, 2, 3, 1, 2, 3],"group": ["a", "a", "a", "b", "b", "b"]}
)df2 = pd.DataFrame({"key": ["b", "c", "d"], "rvalue": [1, 2, 3]})
df1
key | lvalue | group | |
---|---|---|---|
0 | a | 1 | a |
1 | c | 2 | a |
2 | e | 3 | a |
3 | a | 1 | b |
4 | c | 2 | b |
5 | e | 3 | b |
df2
key | rvalue | |
---|---|---|
0 | b | 1 |
1 | c | 2 |
2 | d | 3 |
# df1 df2
# key lvalue group key rvalue
# 0 a 1 a 0 b 1
# 1 c 2 a 1 c 2
# 2 e 3 a 2 d 3
# 3 a 1 b
# 4 c 2 b
# 5 e 3 b
1. 如果 left_by 与 right_by 均为空,等价于 merge
pd.merge_ordered(df1, df2).sort_values(by=["key", "lvalue"], ignore_index=True)
key | lvalue | group | rvalue | |
---|---|---|---|---|
0 | a | 1.0 | a | NaN |
1 | a | 1.0 | b | NaN |
2 | b | NaN | NaN | 1.0 |
3 | c | 2.0 | a | 2.0 |
4 | c | 2.0 | b | 2.0 |
5 | d | NaN | NaN | 3.0 |
6 | e | 3.0 | a | NaN |
7 | e | 3.0 | b | NaN |
等价于如下:
pd.merge(df1, df2, how="outer").sort_values(by=["key", "lvalue"], ignore_index=True)
key | lvalue | group | rvalue | |
---|---|---|---|---|
0 | a | 1.0 | a | NaN |
1 | a | 1.0 | b | NaN |
2 | b | NaN | NaN | 1.0 |
3 | c | 2.0 | a | 2.0 |
4 | c | 2.0 | b | 2.0 |
5 | d | NaN | NaN | 3.0 |
6 | e | 3.0 | a | NaN |
7 | e | 3.0 | b | NaN |
2. 如果 left_by 或 right_by 不为空,会先按这个参数值对 DataFrame 进行分组,将分组后的 DataFrame 再进行连接
pd.merge_ordered(df1, df2, left_by="group")
#第一步:将 df1 根据 group 进行分组
# 第二步:将分组后的 df1 中每一组的数据,通过连接关键字 key 与 df2 进行连接
key | lvalue | group | rvalue | |
---|---|---|---|---|
0 | a | 1.0 | a | NaN |
1 | b | NaN | a | 1.0 |
2 | c | 2.0 | a | 2.0 |
3 | d | NaN | a | 3.0 |
4 | e | 3.0 | a | NaN |
5 | a | 1.0 | b | NaN |
6 | b | NaN | b | 1.0 |
7 | c | 2.0 | b | 2.0 |
8 | d | NaN | b | 3.0 |
9 | e | 3.0 | b | NaN |
pd.merge_ordered(df1, df2, right_by="rvalue")
# 第一步:将 df2 根据 rvalue 进行分组
# 第二步:将分组后的 df2 中每一组的数据,通过连接关键字 key 与 df1 进行连接
key | lvalue | group | rvalue | |
---|---|---|---|---|
0 | a | 1.0 | a | 1 |
1 | a | 1.0 | b | 1 |
2 | b | NaN | NaN | 1 |
3 | c | 2.0 | a | 1 |
4 | c | 2.0 | b | 1 |
5 | e | 3.0 | a | 1 |
6 | e | 3.0 | b | 1 |
7 | a | 1.0 | a | 2 |
8 | a | 1.0 | b | 2 |
9 | c | 2.0 | a | 2 |
10 | c | 2.0 | b | 2 |
11 | e | 3.0 | a | 2 |
12 | e | 3.0 | b | 2 |
13 | a | 1.0 | a | 3 |
14 | a | 1.0 | b | 3 |
15 | c | 2.0 | a | 3 |
16 | c | 2.0 | b | 3 |
17 | d | NaN | NaN | 3 |
18 | e | 3.0 | a | 3 |
19 | e | 3.0 | b | 3 |
3. 如果,“left_by 或 right_by 的值” 与 “连接关键字” 相同,那无论是什么连接方式,结果都一样
pd.merge_ordered(df1, df2, left_by="key")
key | lvalue | group | rvalue | |
---|---|---|---|---|
0 | a | 1 | a | NaN |
1 | a | 1 | b | NaN |
2 | c | 2 | a | 2.0 |
3 | c | 2 | b | 2.0 |
4 | e | 3 | a | NaN |
5 | e | 3 | b | NaN |
pd.merge_ordered(df1, df2, left_by="key", how="inner")
key | lvalue | group | rvalue | |
---|---|---|---|---|
0 | a | 1 | a | NaN |
1 | a | 1 | b | NaN |
2 | c | 2 | a | 2.0 |
3 | c | 2 | b | 2.0 |
4 | e | 3 | a | NaN |
5 | e | 3 | b | NaN |
pd.merge_ordered(df1, df2, left_by="key", how="right")
key | lvalue | group | rvalue | |
---|---|---|---|---|
0 | a | 1 | a | NaN |
1 | a | 1 | b | NaN |
2 | c | 2 | a | 2.0 |
3 | c | 2 | b | 2.0 |
4 | e | 3 | a | NaN |
5 | e | 3 | b | NaN |
6.1.2.2.3 pd.merge_asof()
pandas 的 merge_asof() 类似于有序的LEFT JOIN,只是我们在最近的键上匹配,而不是相等键。
- pd.merge_asof()语法格式:
pandas.merge_asof(left,right,on=None, left_on=None, right_on=None, left_index=False, right_index=False, by=None, left_by=None, right_by=None, suffixes=(‘_x’, ‘_y’), tolerance=None, allow_exact_matches=True, direction=’backward’, )
-
参数说明:
- left, right: DataFrame
- on:标签,要加入的字段名称。必须在两个DataFrame中都找到。
- left_on:标签,要在左侧DataFrame中加入的字段名称。
- right_on:标签,要在右侧DataFrame中加入的字段名称。
- left_index:布尔值,使用左侧DataFrame的索引作为连接键。
- right_index:布尔值,使用正确的DataFrame的索引作为连接键。
-
pd.merge_asof()实例:
# importing package
import pandas # creating data
left = pandas.DataFrame({'a':[1, 5, 10], 'left_val':['a', 'b', 'c']}) right = pandas.DataFrame({'a':[1, 2, 3, 6, 7], 'right_val':[1, 2, 3, 6, 7]}) # view data
print(left)
print(right) # applying merge_asof on data
print(pandas.merge_asof(left, right, on='a'))
print(pandas.merge_asof(left, right, on='a',allow_exact_matches=False))
a left_val
0 1 a
1 5 b
2 10 ca right_val
0 1 1
1 2 2
2 3 3
3 6 6
4 7 7a left_val right_val
0 1 a 1
1 5 b 3
2 10 c 7a left_val right_val
0 1 a NaN
1 5 b 3.0
2 10 c 7.0
6.1.2.3 堆叠合并数据
- dataframe.join(): 根据行索引连接多组数据
- pd.concat(): 沿着某个轴方向堆叠多组数据
- dataframe.append(): 向数据末尾追加若干行数据
6.1.2.3.0 构建数据
import pandas as pd
import numpy as npdf1 = pd.DataFrame({"姓名":["小明","小红","小周"],"年龄":[18,24,20]
})
df1
姓名 | 年龄 | |
---|---|---|
0 | 小明 | 18 |
1 | 小红 | 24 |
2 | 小周 | 20 |
df2 = pd.DataFrame({"姓名":["小孙","小芳"],"年龄":[25,19]
})
df2
姓名 | 年龄 | |
---|---|---|
0 | 小孙 | 25 |
1 | 小芳 | 19 |
df3 = pd.DataFrame({"地址":["深圳","广州","珠海"],"成绩":[600,630,598]
})
df3
地址 | 成绩 | |
---|---|---|
0 | 深圳 | 600 |
1 | 广州 | 630 |
2 | 珠海 | 598 |
df4 = pd.DataFrame({"地址":["深圳","广州","东莞"],"爱好":["乒乓球","羽毛球","高尔夫"]
})
df4
地址 | 爱好 | |
---|---|---|
0 | 深圳 | 乒乓球 |
1 | 广州 | 羽毛球 |
2 | 东莞 | 高尔夫 |
df5 = pd.DataFrame({"地址":["深圳","广州","东莞","上海","北京"],"爱好":["乒乓球","羽毛球","高尔夫","跑步","健身"]
})
df5
地址 | 爱好 | |
---|---|---|
0 | 深圳 | 乒乓球 |
1 | 广州 | 羽毛球 |
2 | 东莞 | 高尔夫 |
3 | 上海 | 跑步 |
4 | 北京 | 健身 |
6.1.2.3.1 pd.concat()
解决两个表或者多个表按照纵向或者横向拼接。
- pd.concat()的语法格式:
pandas.concat(objs, # 合并对象axis=0, # 合并方向,默认是0纵轴方向join='outer', # 合并取的是交集inner还是并集outerignore_index=False, # 合并之后索引是否重新keys=None, # 在行索引的方向上带上原来数据的名字;主要是用于层次化索引,可以是任意的列表、数组、元组或者列表数组levels=None, # 指定用作层次化索引各级别上的索引,如果是设置了keysnames=None, # 行索引的名字,列表形式verify_integrity=False, # 检查行索引是否重复;有则报错sort=False, # 对非连接的轴进行排序copy=True # 是否进行深拷贝)
-
pd.concat()的参数详细说明:
- objs:Series,DataFrame或Panel对象的序列或映射。如果传递了dict,则排序的键将用作键参数,除非它被传递,在这种情况下,将选择值(见下文)。任何无对象将被静默删除,除非它们都是无,在这种情况下将引发一个ValueError。
- axis:{0,1,…},默认为0。沿着连接的轴。
- join:{‘inner’,‘outer’},默认为“outer”。如何处理其他轴上的索引。outer为联合和inner为交集。
- ignore_index:boolean,default False。如果为True,请不要使用并置轴上的索引值。结果轴将被标记为0,…,n-1。如果要连接其中并置轴没有有意义的索引信息的对象,这将非常有用。注意,其他轴上的索引值在连接中仍然受到尊重。
- join_axes:Index对象列表。用于其他n-1轴的特定索引,而不是执行内部/外部设置逻辑。
- keys:序列,默认值无。使用传递的键作为最外层构建层次索引。如果为多索引,应该使用元组。
- levels:序列列表,默认值无。用于构建MultiIndex的特定级别(唯一值)。否则,它们将从键推断。
- names:list,default无。结果层次索引中的级别的名称。
- verify_integrity:boolean,default False。检查新连接的轴是否包含重复项。这相对于实际的数据串联可能是非常昂贵的。
- copy:boolean,default True。如果为False,请勿不必要地复制数据。
-
pd.concat()使用实例:
- 根据实际数据调整合并的方向,默认是axis=0
- 某个数据库中不存在的数据,用NaN代替
- ignore_index是否保留原表索引,默认保留,为 True 会自动增加自然索引。
- 指定取得交集inner还是并集outer,默认是并集outer
1. 默认情况是直接在纵向上进行合并
# 使用原索引
pd.concat([df1,df2])
姓名 | 年龄 | |
---|---|---|
0 | 小明 | 18 |
1 | 小红 | 24 |
2 | 小周 | 20 |
0 | 小孙 | 25 |
1 | 小芳 | 19 |
# ignore_index=True,重新行索引
pd.concat([df1,df2],ignore_index=True)
姓名 | 年龄 | |
---|---|---|
0 | 小明 | 18 |
1 | 小红 | 24 |
2 | 小周 | 20 |
3 | 小孙 | 25 |
4 | 小芳 | 19 |
2. axis指定轴方向上的合并,默认方向axis=0
pd.concat([df1,df2],axis=0) #默认方向
姓名 | 年龄 | |
---|---|---|
0 | 小明 | 18 |
1 | 小红 | 24 |
2 | 小周 | 20 |
0 | 小孙 | 25 |
1 | 小芳 | 19 |
pd.concat([df1,df3],axis=1)
姓名 | 年龄 | 地址 | 成绩 | |
---|---|---|---|---|
0 | 小明 | 18 | 深圳 | 600 |
1 | 小红 | 24 | 广州 | 630 |
2 | 小周 | 20 | 珠海 | 598 |
#缺失填充NaN
pd.concat([df1,df2],axis=1)
姓名 | 年龄 | 姓名 | 年龄 | |
---|---|---|---|---|
0 | 小明 | 18 | 小孙 | 25.0 |
1 | 小红 | 24 | 小芳 | 19.0 |
2 | 小周 | 20 | NaN | NaN |
3. joni参数指定取得交集inner还是并集outer,默认是并集outer
pd.concat([df3,df4],join="outer")
#pd.concat([df3,df4])
地址 | 成绩 | 爱好 | |
---|---|---|---|
0 | 深圳 | 600.0 | NaN |
1 | 广州 | 630.0 | NaN |
2 | 珠海 | 598.0 | NaN |
0 | 深圳 | NaN | 乒乓球 |
1 | 广州 | NaN | 羽毛球 |
2 | 东莞 | NaN | 高尔夫 |
# df3和df4只有地址这个字段是相同的,所以保留了它,其他的舍弃:
pd.concat([df3,df4],join="inner")
地址 | |
---|---|
0 | 深圳 |
1 | 广州 |
2 | 珠海 |
0 | 深圳 |
1 | 广州 |
2 | 东莞 |
4. keys参数传递序列输入,默认值无。使用传递的键作为最外层构建层次索引。
- 当我们设置了索引重排(ignore_index=True),keys参数就无效啦
pd.concat([df1,df2],keys=["df1","df2"])
姓名 | 年龄 | ||
---|---|---|---|
df1 | 0 | 小明 | 18 |
1 | 小红 | 24 | |
2 | 小周 | 20 | |
df2 | 0 | 小孙 | 25 |
1 | 小芳 | 19 |
#当我们设置了索引重排(ignore_index=True),keys参数就无效啦
pd.concat([df1,df2],keys=["df1","df2"],ignore_index=True)
姓名 | 年龄 | |
---|---|---|
0 | 小明 | 18 |
1 | 小红 | 24 |
2 | 小周 | 20 |
3 | 小孙 | 25 |
4 | 小芳 | 19 |
5. name参数,指定每个层级索引名字
df6 = pd.concat([df1,df2],keys=["df1","df2"],names=["D1","D2"])
df6
姓名 | 年龄 | ||
---|---|---|---|
D1 | D2 | ||
df1 | 0 | 小明 | 18 |
1 | 小红 | 24 | |
2 | 小周 | 20 | |
df2 | 0 | 小孙 | 25 |
1 | 小芳 | 19 |
我们可以检查下df6的索引,发现是层级索引:
df6.index
MultiIndex([('df1', 0),('df1', 1),('df1', 2),('df2', 0),('df2', 1)],names=['D1', 'D2'])
6. 合并多个DataFrame
pd.concat([pd.concat([df1,df2],axis=0,ignore_index=True),df5],axis=1)
姓名 | 年龄 | 地址 | 爱好 | |
---|---|---|---|---|
0 | 小明 | 18 | 深圳 | 乒乓球 |
1 | 小红 | 24 | 广州 | 羽毛球 |
2 | 小周 | 20 | 东莞 | 高尔夫 |
3 | 小孙 | 25 | 上海 | 跑步 |
4 | 小芳 | 19 | 北京 | 健身 |
等价于:分两步来实现:先合并df1、df2,将得到的结果和df5合并
df7 = pd.concat([df1,df2],axis=0,ignore_index=True)
df7
姓名 | 年龄 | |
---|---|---|
0 | 小明 | 18 |
1 | 小红 | 24 |
2 | 小周 | 20 |
3 | 小孙 | 25 |
4 | 小芳 | 19 |
pd.concat([df7,df5],axis=1)
姓名 | 年龄 | 地址 | 爱好 | |
---|---|---|---|---|
0 | 小明 | 18 | 深圳 | 乒乓球 |
1 | 小红 | 24 | 广州 | 羽毛球 |
2 | 小周 | 20 | 东莞 | 高尔夫 |
3 | 小孙 | 25 | 上海 | 跑步 |
4 | 小芳 | 19 | 北京 | 健身 |
6.1.2.3.2 dataframe.join()
dataframe内置的join方法是一种快速合并的方法。它默认以index作为对齐的列。
- dataframe.join()的语法格式:
dataframe.join(other, # 待合并的另一个数据框on=None, # 连接的键how='left', # 连接方式:‘left’, ‘right’, ‘outer’, ‘inner’ 默认是leftlsuffix='', # 左边(第一个)数据框相同键的后缀rsuffix='', # 第二个数据框的键的后缀sort=False) # 是否根据连接的键进行排序;默认False
-
dataframe.join()的参数说明:
- other:DataFrame, Series, or list of DataFrame,另外一个dataframe, series,或者dataframe list。
- on: 参与join的列,与sql中的on参数类似。
- how: 连接方法,从{‘left’, ‘right’, ‘outer’, ‘inner’}中选取,默认’left’。
- lsuffix: 左DataFrame中重复列的后缀
- rsuffix: 右DataFrame中重复列的后缀
- sort: 按字典序对结果在连接键上排序
-
join()的各种连接方法图示
-
dataframe.join()使用实例
模拟数据
df10 = pd.DataFrame({"name":["小红","小明","小孙","小周","小张"],"address":["深圳","广州","长沙","上海","苏州"]
})
df10
name | address | |
---|---|---|
0 | 小红 | 深圳 |
1 | 小明 | 广州 |
2 | 小孙 | 长沙 |
3 | 小周 | 上海 |
4 | 小张 | 苏州 |
df11 = pd.DataFrame({"name":["小红","小明","小孙"],"sex":["女","男","男"],"age":[29,23,27]
})
df11
name | sex | age | |
---|---|---|---|
0 | 小红 | 女 | 29 |
1 | 小明 | 男 | 23 |
2 | 小孙 | 男 | 27 |
df12 = pd.DataFrame({"name":["小红","小明"],"height":[173,177]
})
df12
name | height | |
---|---|---|
0 | 小红 | 173 |
1 | 小明 | 177 |
df13 = pd.DataFrame({"name":["小红","小明","小孙"],"sex":["女","男","男"],"score":[600,612,590]
})
df13
name | sex | score | |
---|---|---|---|
0 | 小红 | 女 | 600 |
1 | 小明 | 男 | 612 |
2 | 小孙 | 男 | 590 |
1. lsuffix、rsuffix参数,为了添加指定的后缀
df10.join(df11,lsuffix="_left",rsuffix="_right")
name_left | address | name_right | sex | age | |
---|---|---|---|---|---|
0 | 小红 | 深圳 | 小红 | 女 | 29.0 |
1 | 小明 | 广州 | 小明 | 男 | 23.0 |
2 | 小孙 | 长沙 | 小孙 | 男 | 27.0 |
3 | 小周 | 上海 | NaN | NaN | NaN |
4 | 小张 | 苏州 | NaN | NaN | NaN |
2. how参数指定连接方法,默认是left,保留左边的全部字段,右边不存在的的数据用NaN
df10.join(df11,lsuffix="_left",rsuffix="_right",how="left")
name_left | address | name_right | sex | age | |
---|---|---|---|---|---|
0 | 小红 | 深圳 | 小红 | 女 | 29.0 |
1 | 小明 | 广州 | 小明 | 男 | 23.0 |
2 | 小孙 | 长沙 | 小孙 | 男 | 27.0 |
3 | 小周 | 上海 | NaN | NaN | NaN |
4 | 小张 | 苏州 | NaN | NaN | NaN |
df10.join(df11,lsuffix="_left",rsuffix="_right",how="right")
name_left | address | name_right | sex | age | |
---|---|---|---|---|---|
0 | 小红 | 深圳 | 小红 | 女 | 29 |
1 | 小明 | 广州 | 小明 | 男 | 23 |
2 | 小孙 | 长沙 | 小孙 | 男 | 27 |
3. on参数,指定参与join的列
可以在默认的参数结果中,name字段被分成了name_left和name_right,如何进行字段的合并呢???
-
先把键当做行索引
-
通过join合并
-
通过reset_index()重新设置索引
# 1. 把键当作行索引
df10.set_index("name")
address | |
---|---|
name | |
小红 | 深圳 |
小明 | 广州 |
小孙 | 长沙 |
小周 | 上海 |
小张 | 苏州 |
df11.set_index("name")
sex | age | |
---|---|---|
name | ||
小红 | 女 | 29 |
小明 | 男 | 23 |
小孙 | 男 | 27 |
# 2.合并两个数据
df10.set_index("name").join(df11.set_index("name"))
address | sex | age | |
---|---|---|---|
name | |||
小红 | 深圳 | 女 | 29.0 |
小明 | 广州 | 男 | 23.0 |
小孙 | 长沙 | 男 | 27.0 |
小周 | 上海 | NaN | NaN |
小张 | 苏州 | NaN | NaN |
# 3. 索引重置
df10.set_index("name").join(df11.set_index("name")).reset_index()
name | address | sex | age | |
---|---|---|---|---|
0 | 小红 | 深圳 | 女 | 29.0 |
1 | 小明 | 广州 | 男 | 23.0 |
2 | 小孙 | 长沙 | 男 | 27.0 |
3 | 小周 | 上海 | NaN | NaN |
4 | 小张 | 苏州 | NaN | NaN |
另外一种更为简便的方法:
df10.join(df11.set_index("name"),on="name")
name | address | sex | age | |
---|---|---|---|---|
0 | 小红 | 深圳 | 女 | 29.0 |
1 | 小明 | 广州 | 男 | 23.0 |
2 | 小孙 | 长沙 | 男 | 27.0 |
3 | 小周 | 上海 | NaN | NaN |
4 | 小张 | 苏州 | NaN | NaN |
4. 合并多个DataFrame
df10.set_index("name").join([df11.set_index("name"),df12.set_index("name"),]).reset_index()
name | address | sex | age | height | |
---|---|---|---|---|---|
0 | 小红 | 深圳 | 女 | 29.0 | 173.0 |
1 | 小明 | 广州 | 男 | 23.0 | 177.0 |
2 | 小孙 | 长沙 | 男 | 27.0 | NaN |
3 | 小周 | 上海 | NaN | NaN | NaN |
4 | 小张 | 苏州 | NaN | NaN | NaN |
如果我们想要用merge函数来实现呢?
使用how=“outer”,保留全部字段的数据信息
pd.merge(pd.merge(df10,df11,how="outer"),df12,how="outer")
name | address | sex | age | height | |
---|---|---|---|---|---|
0 | 小红 | 深圳 | 女 | 29.0 | 173.0 |
1 | 小明 | 广州 | 男 | 23.0 | 177.0 |
2 | 小孙 | 长沙 | 男 | 27.0 | NaN |
3 | 小周 | 上海 | NaN | NaN | NaN |
4 | 小张 | 苏州 | NaN | NaN | NaN |
6.1.2.3.3 dataframe.append()
向dataframe对象中添加新的行,如果添加的列名不在dataframe对象中,将会被当作新的列进行添加
- dataframe.append()的语法格式:
DataFrame.append(other, ignore_index=False, verify_integrity=False, sort=False)
-
dataframe.append()的参数详细说明:
- other:DataFrame、series、dict、list这样的数据结构
- ignore_index:默认值为False,如果为True则不使用index标签
- verify_integrity :默认值为False,如果为True当创建相同的index时会抛出ValueError的异常
- sort:boolean,默认是None,该属性在pandas的0.23.0的版本才存在。
-
dataframe.append()的实例
模拟数据
df14= pd.DataFrame([[601,592],[23, 24]],columns=["小明","小红"])
df14
小明 | 小红 | |
---|---|---|
0 | 601 | 592 |
1 | 23 | 24 |
df15 = pd.DataFrame([["男","女"],["深圳","广州"]],columns=["小明","小红"])
df15
小明 | 小红 | |
---|---|---|
0 | 男 | 女 |
1 | 深圳 | 广州 |
1. 添加Python字典
dict1 = {"小明":"乒乓球","小红":"排球"}
df14.append(dict1,ignore_index=True)
小明 | 小红 | |
---|---|---|
0 | 601 | 592 |
1 | 23 | 24 |
2 | 乒乓球 | 排球 |
若不指定ignore_index=True则会出错
2. 添加Series类型
s = pd.Series(dict1)
s
小明 乒乓球
小红 排球
dtype: object
df14.append(s,ignore_index=True)
小明 | 小红 | |
---|---|---|
0 | 601 | 592 |
1 | 23 | 24 |
2 | 乒乓球 | 排球 |
3. 添加DataFrame
df16 = pd.DataFrame(dict1,index=[0])
df16
小明 | 小红 | |
---|---|---|
0 | 乒乓球 | 排球 |
df14.append(df16,ignore_index=True)
小明 | 小红 | |
---|---|---|
0 | 601 | 592 |
1 | 23 | 24 |
2 | 乒乓球 | 排球 |
4. 默认合并
df14.append(df15)
小明 | 小红 | |
---|---|---|
0 | 601 | 592 |
1 | 23 | 24 |
0 | 男 | 女 |
1 | 深圳 | 广州 |
#重新索引
df14.append(df15,ignore_index=True)
小明 | 小红 | |
---|---|---|
0 | 601 | 592 |
1 | 23 | 24 |
2 | 男 | 女 |
3 | 深圳 | 广州 |
5. verify_integrity参数
默认为False,为True,创建相同的index则会抛出异常的错误
df14.append(df15,verify_integrity=True)
---------------------------------------------------------------------------ValueError Traceback (most recent call last)<ipython-input-58-41bb9b875bb2> in <module>
----> 1 df14.append(df15,verify_integrity=True)D:\ProgramFiles\Anaconda3\lib\site-packages\pandas\core\frame.py in append(self, other, ignore_index, verify_integrity, sort)8967 ignore_index=ignore_index,8968 verify_integrity=verify_integrity,
-> 8969 sort=sort,8970 )8971 ).__finalize__(self, method="append")D:\ProgramFiles\Anaconda3\lib\site-packages\pandas\util\_decorators.py in wrapper(*args, **kwargs)309 stacklevel=stacklevel,310 )
--> 311 return func(*args, **kwargs)312 313 return wrapperD:\ProgramFiles\Anaconda3\lib\site-packages\pandas\core\reshape\concat.py in concat(objs, axis, join, ignore_index, keys, levels, names, verify_integrity, sort, copy)302 verify_integrity=verify_integrity,303 copy=copy,
--> 304 sort=sort,305 )306 D:\ProgramFiles\Anaconda3\lib\site-packages\pandas\core\reshape\concat.py in __init__(self, objs, axis, join, keys, levels, names, ignore_index, verify_integrity, copy, sort)477 self.copy = copy478
--> 479 self.new_axes = self._get_new_axes()480 481 def get_result(self):D:\ProgramFiles\Anaconda3\lib\site-packages\pandas\core\reshape\concat.py in _get_new_axes(self)549 return [550 self._get_concat_axis if i == self.bm_axis else self._get_comb_axis(i)
--> 551 for i in range(ndim)552 ]553 D:\ProgramFiles\Anaconda3\lib\site-packages\pandas\core\reshape\concat.py in <listcomp>(.0)549 return [550 self._get_concat_axis if i == self.bm_axis else self._get_comb_axis(i)
--> 551 for i in range(ndim)552 ]553 D:\ProgramFiles\Anaconda3\lib\site-packages\pandas\_libs\properties.pyx in pandas._libs.properties.CachedProperty.__get__()D:\ProgramFiles\Anaconda3\lib\site-packages\pandas\core\reshape\concat.py in _get_concat_axis(self)609 )610
--> 611 self._maybe_check_integrity(concat_axis)612 613 return concat_axisD:\ProgramFiles\Anaconda3\lib\site-packages\pandas\core\reshape\concat.py in _maybe_check_integrity(self, concat_index)617 if not concat_index.is_unique:618 overlap = concat_index[concat_index.duplicated()].unique()
--> 619 raise ValueError(f"Indexes have overlapping values: {overlap}")620 621 ValueError: Indexes have overlapping values: Int64Index([0, 1], dtype='int64')
df14.append(df15,verify_integrity=False)
小明 | 小红 | |
---|---|---|
0 | 601 | 592 |
1 | 23 | 24 |
0 | 男 | 女 |
1 | 深圳 | 广州 |
6.1.2.4 重叠合并数据
当两组数据的索引完全重合或部分重合,且数据中存在缺失值时,可以采用重叠合并的方式组合数据。重叠合并数据是一种并不常见的操作,它主要将一组数据的空值填充为另一组数据中对应位置的值。pandas中可使用combine_first()方法实现重叠合并数据的操作。
6.1.2.4.1 dfbine()
对两个DataFrame进行联合操作,实现合并的功能。
other参数传入被合并的DataFrame,
func参数传入合并的规则函数,两个参数都是必传参数。
func函数的入参是两个Series,分别来自两个DataFrame(将DataFrame按列遍历),返回结果是一个合并之后的Series,在函数中实现合并的规则。
func可以是匿名函数、Python库中定义好的函数、或自定义的函数,要满足两个入参一个返回值,且入参和返回值是数组或Series。如上面的例子中,使用了匿名函数,合并规则为返回两个DataFrame中非空数据更多的列。
- 语法格式:
dfbine(other: 'DataFrame',func,fill_value=None,overwrite: 'bool' = True,
) -> 'DataFrame'
-
参数详细解释:
- other:其他系列或要与调用者系列组合的列表类型
- func:作为参数传递的函数,该函数将决定从哪个系列将元素放入该索引
- fill_value:多索引时级别的整数值
- overwrite:是否使用other中值填充df
-
dfbine()使用实例:
0.构建数据框并定义函数
import pandas as pd
import numpy as np
# 构建两个数据库
df1 = pd.DataFrame({'A': [11, 2, np.nan],'B': [4, np.nan, 6],'C': [7,np.nan,np.nan]},index=['one','two','three'])
df2 = pd.DataFrame({'A': [1, 12, 3], 'B': [np.nan,np.nan,6],'C': [7, 8, np.nan]}, index=['one','two','three'])# 定义匿名函数
take_smaller = lambda x, y: x if x.sum() < y.sum() else y# 定义函数
def take_bigger(x,y):if x.sum()>y.sum():print("x.sum:",x.sum())print("y.sum:",y.sum())print("bigger")print(x)return xelse:print("x.sum:",x.sum())print("y.sum:",y.sum())print("smaller")print(y)return y
df1
A | B | C | |
---|---|---|---|
one | 11.0 | 4.0 | 7.0 |
two | 2.0 | NaN | NaN |
three | NaN | 6.0 | NaN |
df2
A | B | C | |
---|---|---|---|
one | 1 | NaN | 7.0 |
two | 12 | NaN | 8.0 |
three | 3 | 6.0 | NaN |
1. func可以是匿名函数、标准函数或常规自定义函数
# 传递匿名函数
# 取列值和最小的列
# x:df1, y:df2
df1bine(df2, take_smaller, overwrite=False) # df1 中不存在 C,返回 NaN
A | B | C | |
---|---|---|---|
one | 11.0 | NaN | 7.0 |
two | 2.0 | NaN | NaN |
three | NaN | 6.0 | NaN |
# 传递numpy标准函数
# 取各元素最小值
df1bine(df2,np.fmin,overwrite=False)
A | B | C | |
---|---|---|---|
one | 1.0 | 4.0 | 7.0 |
two | 2.0 | NaN | 8.0 |
three | 3.0 | 6.0 | NaN |
# 传递numpy标准函数
# 取各元素最大值
df1bine(df2,np.fmax,overwrite=False)
A | B | C | |
---|---|---|---|
one | 11.0 | 4.0 | 7.0 |
two | 12.0 | NaN | 8.0 |
three | 3.0 | 6.0 | NaN |
# 传递常规自定义函数
# 取列值和最大的列
# x:df1, y:df2
df1bine(df2,take_bigger,overwrite=False)
x.sum: 13.0
y.sum: 16.0
smaller
one 1.0
two 12.0
three 3.0
Name: A, dtype: float64
x.sum: 10.0
y.sum: 6.0
bigger
one 4.0
two NaN
three 6.0
Name: B, dtype: float64
x.sum: 7.0
y.sum: 15.0
smaller
one 7.0
two 8.0
three NaN
Name: C, dtype: float64
A | B | C | |
---|---|---|---|
one | 1.0 | 4.0 | 7.0 |
two | 12.0 | NaN | 8.0 |
three | 3.0 | 6.0 | NaN |
2. 合并时填充空值
fill_value: 先用fill_value填充DataFrame中的空值,再按传入的函数进行合并操作。
fill_value会填充DataFrame中所有列的空值,而且是在合并之前先填充。
# 构建dataframe
df3 = pd.DataFrame({'A':[1,2,np.nan],'B':[4,np.nan,16],'C':[7,np.nan,np.nan]},index=['one','two','three'])
df3
A | B | C | |
---|---|---|---|
one | 1.0 | 4.0 | 7.0 |
two | 2.0 | NaN | NaN |
three | NaN | 16.0 | NaN |
df4 = pd.DataFrame({'A':[11,2,3],'B':[np.nan,np.nan,6],'D':[10,np.nan,12]},index=['one','two','three'])
df4
A | B | D | |
---|---|---|---|
one | 11 | NaN | 10.0 |
two | 2 | NaN | NaN |
three | 3 | 6.0 | 12.0 |
# 定义保留最大值函数
def save_max(s1,s2):s = s1for ind in s1.index:if ind in s2.index and s1[ind] < s2[ind]:s[ind] = s2[ind]return s
df3bine(df4, save_max, fill_value=5)
A | B | C | D | |
---|---|---|---|---|
one | 11.0 | 5.0 | 7.0 | 10.0 |
two | 2.0 | 5.0 | 5.0 | 5.0 |
three | 5.0 | 16.0 | 5.0 | 12.0 |
上面的例子中自定义了函数save_max(),合并时取同位置的最大值,原理如下图。
3. 不处理缺失的列
df3bine(df4,save_max,fill_value=5,overwrite=False)
A | B | C | D | |
---|---|---|---|---|
one | 11.0 | 5.0 | 7.0 | 10.0 |
two | 2.0 | 5.0 | NaN | 5.0 |
three | 5.0 | 16.0 | NaN | 12.0 |
overwrite: 如果调用combine()方法的DataFrame中存在的列,在传入combine()方法的DataFrame中不存在,则先在传入的DataFrame中添加一列空值。overwrite参数默认为True.上一例子中,其填充原理如下:
如果将overwrite参数设置成False,则不会给传入combine()方法的DataFrame添加不存在的列,并且合并时不会处理调用combine()方法的DataFrame中多出的列,多出的列直接原样返回。原理如下图。
再举一个栗子
df5 = pd.DataFrame({'A': [1, 2], 'B': [4, 5]})
df6 = pd.DataFrame({'B': [8, 6], 'C': [1, 7], }, index=[1, 2])
df5,df6
( A B0 1 41 2 5,B C1 8 12 6 7)
df5bine(df6,save_max,overwrite=True,fill_value=3)
A | B | C | |
---|---|---|---|
0 | 3.0 | 4.0 | 3.0 |
1 | 3.0 | 8.0 | 3.0 |
2 | 3.0 | 6.0 | 7.0 |
处理过程如下图:
df5bine(df6,save_max,overwrite=False,fill_value=3)
A | B | C | |
---|---|---|---|
0 | 1.0 | 4.0 | 3.0 |
1 | 2.0 | 8.0 | 3.0 |
2 | NaN | 6.0 | 7.0 |
处理过程如下图:
6.1.2.4.2 dfbine_first()
对两个DataFrame进行联合操作,实现合并的功能,other参数传入被合并的DataFrame。
combine_first()方法根据DataFrame的行索引和列索引,对比两个DataFrame中相同位置的数据,优先取非空的数据进行合并。
如果调用combine_first()方法的df1中数据非空,则结果保留df1中的数据;
如果df1中的数据为空值且传入combine_first()方法的df2中数据非空,则结果取df2中的数据;
如果df1和df2中的数据都为空值,则结果保留df1中的空值(空值有三种: np.nan、None 和 pd.NaT)。
即使两个DataFrame的形状不相同也不受影响,联合时主要是根据索引来定位数据的位置。
df1,df2
( A B Cone 11.0 4.0 7.0two 2.0 NaN NaNthree NaN 6.0 NaN,A B Cone 1 NaN 7.0two 12 NaN 8.0three 3 6.0 NaN)
df1bine_first(df2)
A | B | C | |
---|---|---|---|
one | 11.0 | 4.0 | 7.0 |
two | 2.0 | NaN | 8.0 |
three | 3.0 | 6.0 | NaN |
df2bine_first(df1)
A | B | C | |
---|---|---|---|
one | 1.0 | 4.0 | 7.0 |
two | 12.0 | NaN | 8.0 |
three | 3.0 | 6.0 | NaN |
6.1.2.5 数据合并应用案例
xsjc.xlxs 表中有3个表单:student,course与student_course,分别记录了学生信息、课程信息与选课信息。如下:
现在我们通过合并函数将3个sheet中的内容关联起来
6.1.2.5.1 读取数据并查看基本信息
import pandas as pd
import numpy as np df_student = pd.read_excel("xscj.xlsx",sheet_name="student")
df_course = pd.read_excel("xscj.xlsx",sheet_name="course")
df_stuCourse = pd.read_excel("xscj.xlsx",sheet_name=2)
# 查看前5行
df_student.head()
学号 | 姓名 | 专业 | 性别 | 出生年月 | 总学分 | 备注 | |
---|---|---|---|---|---|---|---|
0 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN |
1 | 81102 | 程明 | 计算机 | 1 | 1991-02-01 | 58 | NaN |
2 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN |
3 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN |
4 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN |
# 查看前5行
df_course.head()
课程号 | 课程名 | 开课学期 | 学时 | 学分 | |
---|---|---|---|---|---|
0 | 101 | 计算机基础 | 1 | 80 | 5 |
1 | 102 | 程序设计与语言 | 2 | 68 | 4 |
2 | 206 | 离散数学 | 4 | 68 | 4 |
3 | 208 | 数据结构 | 5 | 68 | 4 |
4 | 209 | 操作系统 | 6 | 68 | 4 |
# 查看前5行
df_stuCourse.head()
学号 | 课程号 | 成绩 | |
---|---|---|---|
0 | 81101 | 101 | 80 |
1 | 81101 | 102 | 78 |
2 | 81101 | 206 | 76 |
3 | 81102 | 102 | 78 |
4 | 81102 | 206 | 78 |
#查看数据总体信息
df_student.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 23 entries, 0 to 22
Data columns (total 7 columns):# Column Non-Null Count Dtype
--- ------ -------------- ----- 0 学号 23 non-null int64 1 姓名 23 non-null object 2 专业 23 non-null object 3 性别 23 non-null int64 4 出生年月 23 non-null datetime64[ns]5 总学分 23 non-null int64 6 备注 7 non-null object
dtypes: datetime64[ns](1), int64(3), object(3)
memory usage: 1.4+ KB
#查看数据总体信息
df_course.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 9 entries, 0 to 8
Data columns (total 5 columns):# Column Non-Null Count Dtype
--- ------ -------------- ----- 0 课程号 9 non-null int64 1 课程名 9 non-null object2 开课学期 9 non-null int64 3 学时 9 non-null int64 4 学分 9 non-null int64
dtypes: int64(4), object(1)
memory usage: 488.0+ bytes
#查看数据总体信息
df_stuCourse.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 41 entries, 0 to 40
Data columns (total 3 columns):# Column Non-Null Count Dtype
--- ------ -------------- ----- 0 学号 41 non-null int64 1 课程号 41 non-null int64 2 成绩 41 non-null object
dtypes: int64(2), object(1)
memory usage: 1.1+ KB
注意查看上面信息,成绩本应为数值,这里是object,应该是有非数存在
用**pd.to_numeric()**转换成数字,可见其31行是字符“作弊”
6.1.2.5.2 处理缺失值
pd.to_numeric(df_stuCourse['成绩'])
---------------------------------------------------------------------------ValueError Traceback (most recent call last)D:\ProgramFiles\Anaconda3\lib\site-packages\pandas\_libs\lib.pyx in pandas._libs.lib.maybe_convert_numeric()ValueError: Unable to parse string "作弊"During handling of the above exception, another exception occurred:ValueError Traceback (most recent call last)<ipython-input-91-a53b09b91987> in <module>
----> 1 pd.to_numeric(df_stuCourse['成绩'])D:\ProgramFiles\Anaconda3\lib\site-packages\pandas\core\tools\numeric.py in to_numeric(arg, errors, downcast)182 try:183 values, _ = lib.maybe_convert_numeric(
--> 184 values, set(), coerce_numeric=coerce_numeric185 )186 except (ValueError, TypeError):D:\ProgramFiles\Anaconda3\lib\site-packages\pandas\_libs\lib.pyx in pandas._libs.lib.maybe_convert_numeric()ValueError: Unable to parse string "作弊" at position 31
df_stuCourse["成绩"][31]
'作弊'
# 采用errors="coerce"强制转换
df_stuCourse['成绩']=pd.to_numeric(df_stuCourse['成绩'],errors='coerce')
df_stuCourse.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 41 entries, 0 to 40
Data columns (total 3 columns):# Column Non-Null Count Dtype
--- ------ -------------- ----- 0 学号 41 non-null int64 1 课程号 41 non-null int64 2 成绩 40 non-null float64
dtypes: float64(1), int64(2)
memory usage: 1.1 KB
可以看到,"成绩"有一个缺失值,是"作弊"所致。
df_stuCourse["成绩"][31]
nan
# "作弊"给0分
df_stuCourse=df_stuCourse.fillna(0)
df_stuCourse["成绩"][31]
0.0
6.1.2.5.3 合并"student”表与“student_course"表
df_student_stuCourse = pd.merge(df_student,df_stuCourse,how="outer")
df_student_stuCourse
学号 | 姓名 | 专业 | 性别 | 出生年月 | 总学分 | 备注 | 课程号 | 成绩 | |
---|---|---|---|---|---|---|---|---|---|
0 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 101.0 | 80.0 |
1 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 102.0 | 78.0 |
2 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 206.0 | 76.0 |
3 | 81102 | 程明 | 计算机 | 1 | 1991-02-01 | 58 | NaN | 102.0 | 78.0 |
4 | 81102 | 程明 | 计算机 | 1 | 1991-02-01 | 58 | NaN | 206.0 | 78.0 |
5 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 101.0 | 52.0 |
6 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 102.0 | 70.0 |
7 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 206.0 | 81.0 |
8 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 101.0 | 90.0 |
9 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 102.0 | 84.0 |
10 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 206.0 | 65.0 |
11 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 101.0 | 59.0 |
12 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 102.0 | 71.0 |
13 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 206.0 | 81.0 |
14 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 101.0 | 78.0 |
15 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 102.0 | 80.0 |
16 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 206.0 | 68.0 |
17 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 101.0 | 85.0 |
18 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 102.0 | 55.0 |
19 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 206.0 | 87.0 |
20 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 101.0 | 66.0 |
21 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 102.0 | 83.0 |
22 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 206.0 | 70.0 |
23 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 101.0 | 95.0 |
24 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 102.0 | 90.0 |
25 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 206.0 | 89.0 |
26 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 101.0 | 91.0 |
27 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 102.0 | 70.0 |
28 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 206.0 | 76.0 |
29 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 101.0 | 63.0 |
30 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 102.0 | 79.0 |
31 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 206.0 | 0.0 |
32 | 81201 | 王敏 | 通信工程 | 1 | 1989-06-10 | 42 | NaN | 101.0 | 80.0 |
33 | 81202 | 王林 | 通信工程 | 1 | 1989-01-29 | 40 | 有一门课不及格,待补考 | 101.0 | 58.0 |
34 | 81203 | 王玉民 | 通信工程 | 1 | 1990-03-26 | 52 | NaN | 101.0 | 87.0 |
35 | 81204 | 马琳琳 | 通信工程 | 0 | 1989-02-10 | 52 | NaN | 101.0 | 91.0 |
36 | 81206 | 李计 | 通信工程 | 1 | 1989-09-20 | 52 | NaN | NaN | NaN |
37 | 81210 | 李红庆 | 通信工程 | 1 | 1989-05-01 | 54 | 已提前修完一门课,并获得学分 | 101.0 | 76.0 |
38 | 81216 | 孙祥欣 | 通信工程 | 1 | 1989-03-09 | 52 | NaN | 101.0 | 81.0 |
39 | 81218 | 孙研 | 通信工程 | 1 | 1990-10-09 | 52 | NaN | 101.0 | 70.0 |
40 | 81220 | 吴薇华 | 通信工程 | 0 | 1990-03-18 | 52 | NaN | 101.0 | 82.0 |
41 | 81221 | 刘燕敏 | 通信工程 | 0 | 1989-11-12 | 52 | NaN | 101.0 | 76.0 |
42 | 81251 | 罗林琳 | 通信工程 | 0 | 1990-01-30 | 60 | 转专业学习 | NaN | NaN |
43 | 81255 | 李牧 | 计算机 | 1 | 1990-10-14 | 58 | NaN | NaN | NaN |
采用outer方式连接,考虑考虑课程号为"NaN"的意义???
课程号为"NaN"意味着该生没有选课,选课表中无记录。
请找出没有选修课程的学生
df_student_stuCourse[["学号",'姓名',"专业"]][df_student_stuCourse['课程号'].isna()]
学号 | 姓名 | 专业 | |
---|---|---|---|
36 | 81206 | 李计 | 通信工程 |
42 | 81251 | 罗林琳 | 通信工程 |
43 | 81255 | 李牧 | 计算机 |
也可以采用右连接方式
# 采用"right"方式连接
df_student_stuCourse2 = pd.merge(df_student,df_stuCourse,how="right")
df_student_stuCourse2
学号 | 姓名 | 专业 | 性别 | 出生年月 | 总学分 | 备注 | 课程号 | 成绩 | |
---|---|---|---|---|---|---|---|---|---|
0 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 101 | 80.0 |
1 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 102 | 78.0 |
2 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 206 | 76.0 |
3 | 81102 | 程明 | 计算机 | 1 | 1991-02-01 | 58 | NaN | 102 | 78.0 |
4 | 81102 | 程明 | 计算机 | 1 | 1991-02-01 | 58 | NaN | 206 | 78.0 |
5 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 101 | 52.0 |
6 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 102 | 70.0 |
7 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 206 | 81.0 |
8 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 101 | 90.0 |
9 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 102 | 84.0 |
10 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 206 | 65.0 |
11 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 101 | 59.0 |
12 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 102 | 71.0 |
13 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 206 | 81.0 |
14 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 101 | 78.0 |
15 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 102 | 80.0 |
16 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 206 | 68.0 |
17 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 101 | 85.0 |
18 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 102 | 55.0 |
19 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 206 | 87.0 |
20 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 101 | 66.0 |
21 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 102 | 83.0 |
22 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 206 | 70.0 |
23 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 101 | 95.0 |
24 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 102 | 90.0 |
25 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 206 | 89.0 |
26 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 101 | 91.0 |
27 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 102 | 70.0 |
28 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 206 | 76.0 |
29 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 101 | 63.0 |
30 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 102 | 79.0 |
31 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 206 | 0.0 |
32 | 81201 | 王敏 | 通信工程 | 1 | 1989-06-10 | 42 | NaN | 101 | 80.0 |
33 | 81202 | 王林 | 通信工程 | 1 | 1989-01-29 | 40 | 有一门课不及格,待补考 | 101 | 58.0 |
34 | 81203 | 王玉民 | 通信工程 | 1 | 1990-03-26 | 52 | NaN | 101 | 87.0 |
35 | 81204 | 马琳琳 | 通信工程 | 0 | 1989-02-10 | 52 | NaN | 101 | 91.0 |
36 | 81210 | 李红庆 | 通信工程 | 1 | 1989-05-01 | 54 | 已提前修完一门课,并获得学分 | 101 | 76.0 |
37 | 81216 | 孙祥欣 | 通信工程 | 1 | 1989-03-09 | 52 | NaN | 101 | 81.0 |
38 | 81218 | 孙研 | 通信工程 | 1 | 1990-10-09 | 52 | NaN | 101 | 70.0 |
39 | 81220 | 吴薇华 | 通信工程 | 0 | 1990-03-18 | 52 | NaN | 101 | 82.0 |
40 | 81221 | 刘燕敏 | 通信工程 | 0 | 1989-11-12 | 52 | NaN | 101 | 76.0 |
6.1.2.5.4 合并"student”表与“student_course"表合并的结果与“course”表
df_student_stuCourse.join(df_course.set_index("课程号"),on="课程号")
学号 | 姓名 | 专业 | 性别 | 出生年月 | 总学分 | 备注 | 课程号 | 成绩 | 课程名 | 开课学期 | 学时 | 学分 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 101.0 | 80.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
1 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 102.0 | 78.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
2 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 206.0 | 76.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
3 | 81102 | 程明 | 计算机 | 1 | 1991-02-01 | 58 | NaN | 102.0 | 78.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
4 | 81102 | 程明 | 计算机 | 1 | 1991-02-01 | 58 | NaN | 206.0 | 78.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
5 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 101.0 | 52.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
6 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 102.0 | 70.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
7 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 206.0 | 81.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
8 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 101.0 | 90.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
9 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 102.0 | 84.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
10 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 206.0 | 65.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
11 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 101.0 | 59.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
12 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 102.0 | 71.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
13 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 206.0 | 81.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
14 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 101.0 | 78.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
15 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 102.0 | 80.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
16 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 206.0 | 68.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
17 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 101.0 | 85.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
18 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 102.0 | 55.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
19 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 206.0 | 87.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
20 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 101.0 | 66.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
21 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 102.0 | 83.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
22 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 206.0 | 70.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
23 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 101.0 | 95.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
24 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 102.0 | 90.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
25 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 206.0 | 89.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
26 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 101.0 | 91.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
27 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 102.0 | 70.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
28 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 206.0 | 76.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
29 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 101.0 | 63.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
30 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 102.0 | 79.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
31 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 206.0 | 0.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
32 | 81201 | 王敏 | 通信工程 | 1 | 1989-06-10 | 42 | NaN | 101.0 | 80.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
33 | 81202 | 王林 | 通信工程 | 1 | 1989-01-29 | 40 | 有一门课不及格,待补考 | 101.0 | 58.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
34 | 81203 | 王玉民 | 通信工程 | 1 | 1990-03-26 | 52 | NaN | 101.0 | 87.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
35 | 81204 | 马琳琳 | 通信工程 | 0 | 1989-02-10 | 52 | NaN | 101.0 | 91.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
36 | 81206 | 李计 | 通信工程 | 1 | 1989-09-20 | 52 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
37 | 81210 | 李红庆 | 通信工程 | 1 | 1989-05-01 | 54 | 已提前修完一门课,并获得学分 | 101.0 | 76.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
38 | 81216 | 孙祥欣 | 通信工程 | 1 | 1989-03-09 | 52 | NaN | 101.0 | 81.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
39 | 81218 | 孙研 | 通信工程 | 1 | 1990-10-09 | 52 | NaN | 101.0 | 70.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
40 | 81220 | 吴薇华 | 通信工程 | 0 | 1990-03-18 | 52 | NaN | 101.0 | 82.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
41 | 81221 | 刘燕敏 | 通信工程 | 0 | 1989-11-12 | 52 | NaN | 101.0 | 76.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
42 | 81251 | 罗林琳 | 通信工程 | 0 | 1990-01-30 | 60 | 转专业学习 | NaN | NaN | NaN | NaN | NaN | NaN |
43 | 81255 | 李牧 | 计算机 | 1 | 1990-10-14 | 58 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
df_student_stuCourse2.join(df_course.set_index("课程号"),on="课程号")
学号 | 姓名 | 专业 | 性别 | 出生年月 | 总学分 | 备注 | 课程号 | 成绩 | 课程名 | 开课学期 | 学时 | 学分 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 101 | 80.0 | 计算机基础 | 1 | 80 | 5 |
1 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 102 | 78.0 | 程序设计与语言 | 2 | 68 | 4 |
2 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 206 | 76.0 | 离散数学 | 4 | 68 | 4 |
3 | 81102 | 程明 | 计算机 | 1 | 1991-02-01 | 58 | NaN | 102 | 78.0 | 程序设计与语言 | 2 | 68 | 4 |
4 | 81102 | 程明 | 计算机 | 1 | 1991-02-01 | 58 | NaN | 206 | 78.0 | 离散数学 | 4 | 68 | 4 |
5 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 101 | 52.0 | 计算机基础 | 1 | 80 | 5 |
6 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 102 | 70.0 | 程序设计与语言 | 2 | 68 | 4 |
7 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 206 | 81.0 | 离散数学 | 4 | 68 | 4 |
8 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 101 | 90.0 | 计算机基础 | 1 | 80 | 5 |
9 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 102 | 84.0 | 程序设计与语言 | 2 | 68 | 4 |
10 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 206 | 65.0 | 离散数学 | 4 | 68 | 4 |
11 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 101 | 59.0 | 计算机基础 | 1 | 80 | 5 |
12 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 102 | 71.0 | 程序设计与语言 | 2 | 68 | 4 |
13 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 206 | 81.0 | 离散数学 | 4 | 68 | 4 |
14 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 101 | 78.0 | 计算机基础 | 1 | 80 | 5 |
15 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 102 | 80.0 | 程序设计与语言 | 2 | 68 | 4 |
16 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 206 | 68.0 | 离散数学 | 4 | 68 | 4 |
17 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 101 | 85.0 | 计算机基础 | 1 | 80 | 5 |
18 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 102 | 55.0 | 程序设计与语言 | 2 | 68 | 4 |
19 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 206 | 87.0 | 离散数学 | 4 | 68 | 4 |
20 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 101 | 66.0 | 计算机基础 | 1 | 80 | 5 |
21 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 102 | 83.0 | 程序设计与语言 | 2 | 68 | 4 |
22 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 206 | 70.0 | 离散数学 | 4 | 68 | 4 |
23 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 101 | 95.0 | 计算机基础 | 1 | 80 | 5 |
24 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 102 | 90.0 | 程序设计与语言 | 2 | 68 | 4 |
25 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 206 | 89.0 | 离散数学 | 4 | 68 | 4 |
26 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 101 | 91.0 | 计算机基础 | 1 | 80 | 5 |
27 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 102 | 70.0 | 程序设计与语言 | 2 | 68 | 4 |
28 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 206 | 76.0 | 离散数学 | 4 | 68 | 4 |
29 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 101 | 63.0 | 计算机基础 | 1 | 80 | 5 |
30 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 102 | 79.0 | 程序设计与语言 | 2 | 68 | 4 |
31 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 206 | 0.0 | 离散数学 | 4 | 68 | 4 |
32 | 81201 | 王敏 | 通信工程 | 1 | 1989-06-10 | 42 | NaN | 101 | 80.0 | 计算机基础 | 1 | 80 | 5 |
33 | 81202 | 王林 | 通信工程 | 1 | 1989-01-29 | 40 | 有一门课不及格,待补考 | 101 | 58.0 | 计算机基础 | 1 | 80 | 5 |
34 | 81203 | 王玉民 | 通信工程 | 1 | 1990-03-26 | 52 | NaN | 101 | 87.0 | 计算机基础 | 1 | 80 | 5 |
35 | 81204 | 马琳琳 | 通信工程 | 0 | 1989-02-10 | 52 | NaN | 101 | 91.0 | 计算机基础 | 1 | 80 | 5 |
36 | 81210 | 李红庆 | 通信工程 | 1 | 1989-05-01 | 54 | 已提前修完一门课,并获得学分 | 101 | 76.0 | 计算机基础 | 1 | 80 | 5 |
37 | 81216 | 孙祥欣 | 通信工程 | 1 | 1989-03-09 | 52 | NaN | 101 | 81.0 | 计算机基础 | 1 | 80 | 5 |
38 | 81218 | 孙研 | 通信工程 | 1 | 1990-10-09 | 52 | NaN | 101 | 70.0 | 计算机基础 | 1 | 80 | 5 |
39 | 81220 | 吴薇华 | 通信工程 | 0 | 1990-03-18 | 52 | NaN | 101 | 82.0 | 计算机基础 | 1 | 80 | 5 |
40 | 81221 | 刘燕敏 | 通信工程 | 0 | 1989-11-12 | 52 | NaN | 101 | 76.0 | 计算机基础 | 1 | 80 | 5 |
一次性连接多表
df_student.join(df_stuCourse.set_index("学号"),on="学号").join(df_course.set_index("课程号"),on="课程号").reset_index()
index | 学号 | 姓名 | 专业 | 性别 | 出生年月 | 总学分 | 备注 | 课程号 | 成绩 | 课程名 | 开课学期 | 学时 | 学分 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 101.0 | 80.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
1 | 0 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 102.0 | 78.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
2 | 0 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 206.0 | 76.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
3 | 1 | 81102 | 程明 | 计算机 | 1 | 1991-02-01 | 58 | NaN | 102.0 | 78.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
4 | 1 | 81102 | 程明 | 计算机 | 1 | 1991-02-01 | 58 | NaN | 206.0 | 78.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
5 | 2 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 101.0 | 52.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
6 | 2 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 102.0 | 70.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
7 | 2 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 206.0 | 81.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
8 | 3 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 101.0 | 90.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
9 | 3 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 102.0 | 84.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
10 | 3 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 206.0 | 65.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
11 | 4 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 101.0 | 59.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
12 | 4 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 102.0 | 71.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
13 | 4 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 206.0 | 81.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
14 | 5 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 101.0 | 78.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
15 | 5 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 102.0 | 80.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
16 | 5 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 206.0 | 68.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
17 | 6 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 101.0 | 85.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
18 | 6 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 102.0 | 55.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
19 | 6 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 206.0 | 87.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
20 | 7 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 101.0 | 66.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
21 | 7 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 102.0 | 83.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
22 | 7 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 206.0 | 70.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
23 | 8 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 101.0 | 95.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
24 | 8 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 102.0 | 90.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
25 | 8 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 206.0 | 89.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
26 | 9 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 101.0 | 91.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
27 | 9 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 102.0 | 70.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
28 | 9 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 206.0 | 76.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
29 | 10 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 101.0 | 63.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
30 | 10 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 102.0 | 79.0 | 程序设计与语言 | 2.0 | 68.0 | 4.0 |
31 | 10 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 206.0 | 0.0 | 离散数学 | 4.0 | 68.0 | 4.0 |
32 | 11 | 81201 | 王敏 | 通信工程 | 1 | 1989-06-10 | 42 | NaN | 101.0 | 80.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
33 | 12 | 81202 | 王林 | 通信工程 | 1 | 1989-01-29 | 40 | 有一门课不及格,待补考 | 101.0 | 58.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
34 | 13 | 81203 | 王玉民 | 通信工程 | 1 | 1990-03-26 | 52 | NaN | 101.0 | 87.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
35 | 14 | 81204 | 马琳琳 | 通信工程 | 0 | 1989-02-10 | 52 | NaN | 101.0 | 91.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
36 | 15 | 81206 | 李计 | 通信工程 | 1 | 1989-09-20 | 52 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
37 | 16 | 81210 | 李红庆 | 通信工程 | 1 | 1989-05-01 | 54 | 已提前修完一门课,并获得学分 | 101.0 | 76.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
38 | 17 | 81216 | 孙祥欣 | 通信工程 | 1 | 1989-03-09 | 52 | NaN | 101.0 | 81.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
39 | 18 | 81218 | 孙研 | 通信工程 | 1 | 1990-10-09 | 52 | NaN | 101.0 | 70.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
40 | 19 | 81220 | 吴薇华 | 通信工程 | 0 | 1990-03-18 | 52 | NaN | 101.0 | 82.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
41 | 20 | 81221 | 刘燕敏 | 通信工程 | 0 | 1989-11-12 | 52 | NaN | 101.0 | 76.0 | 计算机基础 | 1.0 | 80.0 | 5.0 |
42 | 21 | 81251 | 罗林琳 | 通信工程 | 0 | 1990-01-30 | 60 | 转专业学习 | NaN | NaN | NaN | NaN | NaN | NaN |
43 | 22 | 81255 | 李牧 | 计算机 | 1 | 1990-10-14 | 58 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
df_student.join(df_stuCourse.set_index("学号"),on="学号",how="inner").join(df_course.set_index("课程号"),on="课程号").reset_index()
index | 学号 | 姓名 | 专业 | 性别 | 出生年月 | 总学分 | 备注 | 课程号 | 成绩 | 课程名 | 开课学期 | 学时 | 学分 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 101 | 80.0 | 计算机基础 | 1 | 80 | 5 |
1 | 0 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 102 | 78.0 | 程序设计与语言 | 2 | 68 | 4 |
2 | 0 | 81101 | 刘华 | 通信工程 | 1 | 1991-03-08 | 58 | NaN | 206 | 76.0 | 离散数学 | 4 | 68 | 4 |
3 | 1 | 81102 | 程明 | 计算机 | 1 | 1991-02-01 | 58 | NaN | 102 | 78.0 | 程序设计与语言 | 2 | 68 | 4 |
4 | 1 | 81102 | 程明 | 计算机 | 1 | 1991-02-01 | 58 | NaN | 206 | 78.0 | 离散数学 | 4 | 68 | 4 |
5 | 2 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 101 | 52.0 | 计算机基础 | 1 | 80 | 5 |
6 | 2 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 102 | 70.0 | 程序设计与语言 | 2 | 68 | 4 |
7 | 2 | 81103 | 王燕 | 计算机 | 0 | 1989-10-06 | 58 | NaN | 206 | 81.0 | 离散数学 | 4 | 68 | 4 |
8 | 3 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 101 | 90.0 | 计算机基础 | 1 | 80 | 5 |
9 | 3 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 102 | 84.0 | 程序设计与语言 | 2 | 68 | 4 |
10 | 3 | 81104 | 韦严平 | 计算机 | 1 | 1990-08-26 | 58 | NaN | 206 | 65.0 | 离散数学 | 4 | 68 | 4 |
11 | 4 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 101 | 59.0 | 计算机基础 | 1 | 80 | 5 |
12 | 4 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 102 | 71.0 | 程序设计与语言 | 2 | 68 | 4 |
13 | 4 | 81106 | 李方方 | 计算机 | 1 | 1990-11-20 | 58 | NaN | 206 | 81.0 | 离散数学 | 4 | 68 | 4 |
14 | 5 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 101 | 78.0 | 计算机基础 | 1 | 80 | 5 |
15 | 5 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 102 | 80.0 | 程序设计与语言 | 2 | 68 | 4 |
16 | 5 | 81107 | 李明 | 计算机 | 1 | 1990-05-01 | 62 | 提前修完《数据结构》,并获学分 | 206 | 68.0 | 离散数学 | 4 | 68 | 4 |
17 | 6 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 101 | 85.0 | 计算机基础 | 1 | 80 | 5 |
18 | 6 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 102 | 55.0 | 程序设计与语言 | 2 | 68 | 4 |
19 | 6 | 81108 | 林一帆 | 计算机 | 1 | 1989-08-05 | 60 | 已提前修完一门课 | 206 | 87.0 | 离散数学 | 4 | 68 | 4 |
20 | 7 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 101 | 66.0 | 计算机基础 | 1 | 80 | 5 |
21 | 7 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 102 | 83.0 | 程序设计与语言 | 2 | 68 | 4 |
22 | 7 | 81109 | 张强民 | 计算机 | 1 | 1989-08-11 | 58 | NaN | 206 | 70.0 | 离散数学 | 4 | 68 | 4 |
23 | 8 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 101 | 95.0 | 计算机基础 | 1 | 80 | 5 |
24 | 8 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 102 | 90.0 | 程序设计与语言 | 2 | 68 | 4 |
25 | 8 | 81110 | 张蔚 | 计算机 | 0 | 1991-07-22 | 58 | 三好生 | 206 | 89.0 | 离散数学 | 4 | 68 | 4 |
26 | 9 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 101 | 91.0 | 计算机基础 | 1 | 80 | 5 |
27 | 9 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 102 | 70.0 | 程序设计与语言 | 2 | 68 | 4 |
28 | 9 | 81111 | 赵琳 | 计算机 | 0 | 1990-03-18 | 58 | NaN | 206 | 76.0 | 离散数学 | 4 | 68 | 4 |
29 | 10 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 101 | 63.0 | 计算机基础 | 1 | 80 | 5 |
30 | 10 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 102 | 79.0 | 程序设计与语言 | 2 | 68 | 4 |
31 | 10 | 81113 | 严红 | 计算机 | 0 | 1989-08-11 | 56 | 有一门功课不及格,待补考 | 206 | 0.0 | 离散数学 | 4 | 68 | 4 |
32 | 11 | 81201 | 王敏 | 通信工程 | 1 | 1989-06-10 | 42 | NaN | 101 | 80.0 | 计算机基础 | 1 | 80 | 5 |
33 | 12 | 81202 | 王林 | 通信工程 | 1 | 1989-01-29 | 40 | 有一门课不及格,待补考 | 101 | 58.0 | 计算机基础 | 1 | 80 | 5 |
34 | 13 | 81203 | 王玉民 | 通信工程 | 1 | 1990-03-26 | 52 | NaN | 101 | 87.0 | 计算机基础 | 1 | 80 | 5 |
35 | 14 | 81204 | 马琳琳 | 通信工程 | 0 | 1989-02-10 | 52 | NaN | 101 | 91.0 | 计算机基础 | 1 | 80 | 5 |
36 | 16 | 81210 | 李红庆 | 通信工程 | 1 | 1989-05-01 | 54 | 已提前修完一门课,并获得学分 | 101 | 76.0 | 计算机基础 | 1 | 80 | 5 |
37 | 17 | 81216 | 孙祥欣 | 通信工程 | 1 | 1989-03-09 | 52 | NaN | 101 | 81.0 | 计算机基础 | 1 | 80 | 5 |
38 | 18 | 81218 | 孙研 | 通信工程 | 1 | 1990-10-09 | 52 | NaN | 101 | 70.0 | 计算机基础 | 1 | 80 | 5 |
39 | 19 | 81220 | 吴薇华 | 通信工程 | 0 | 1990-03-18 | 52 | NaN | 101 | 82.0 | 计算机基础 | 1 | 80 | 5 |
40 | 20 | 81221 | 刘燕敏 | 通信工程 | 0 | 1989-11-12 | 52 | NaN | 101 | 76.0 | 计算机基础 | 1 | 80 | 5 |
6.2 数据变换
6.2.1 数据变换概述
在对数据进行分析或挖掘之前,数据必须满足一定的条件,比如方差分析时要求数据具有正态性、方差齐性、独立性、无偏性,需进行诸如平方根、对数、平方根反正弦操作,实现从一种形式到另一种“适当”形式的变换,以适用于分析或挖掘的需求,这一过程就是数据变换。
数据变换主要是从数据中找到特征表示,通过一些转换方法减少有效变量的数目或找到数据的不变式,常见的操作可以分为数据标准化处理、数据离散化处理和数据泛化处理三类。
6.2.1.1 数据标准化处理
数据标准化处理是将数据按照一定的比例缩放,使之投射到一个比较小的特定区间。
常用的数据标准化处理有:最小-最大标准化、均值标准化(Z-Score)、小数定标标准化。
- 小数定标标准化
通过移动小数点的位置来进行规范化。小数点移动的位数取决于该属性数据取值的最大绝对值。
例如:属性A的取值范围是-800到70,那么就可以将数据的小数点整体向左移三位即[-0.8,0.07]
利用numpy对数据进行小数定标规范化的方法如下:
j = np.ceil(np.log10(np.max(abs(x))))scaled_x = x/(10**j)
6.2.1.2 数据离散化处理
数据离散化处理一般是在数据的取值范围内设定若干个离散的划分点,将取值范围划分为若干离散化的区间,分别用不同的符号或整数值代表落在每个子区间的数值。
常用的数据离散化方法主要有等宽法、等频法。
6.2.1.3 数据泛化处理
数据泛化处理指用高层次概念取代低层次概念的数据。
例如,年龄是一个低层次的概念,它经过泛化处理后会变成诸如青年、中年等高层次的概念。
6.2.1.4 Pandas中有关数据变换的基本操作
- 轴向旋装
- 分组与聚合
- 哑变量处理
- 面元划分
6.2.2 Pandas 数据标准化处理操作
6.2.2.1 最小-最大标准化(Min-Max Normalization)
-
计算公式:
X n o r m = X − X m i n X m a x − X m i n X_{norm} = \frac{X-X_{min}}{X_{max}-X_{min}} Xnorm=Xmax−XminX−Xmin
该操作将数据值映射到[0, 1]
-
特点:
- 转化之后,大数据还是较大的,小数据还是较小的
- 当数据为最小值,转化为的数据为0
- 极差过大—>分母过大—>整体的数据偏小 —之间差异不太明显
- 如果数据中的某个数值很大,分母很大,–整体趋向于0
-
实现方法:
- 自定义函数方式:
import pandas as pd
import numpy as np
# 实现最小-最大标准化
def min_max_sca(data):"""最小标准化:param data: series/dataframe:return: 标准化之后的数据"""data = (data - data.min()) / (data.max() - data.min())return data
-
实现方法:
2. sklearn的MinMaxScaler方法from sklearn.preprocessing import MinMaxScalertool = MinMaxScaler(feature_range=(0, 1)) #根据需要设置最大最小值,这里设置最大值为1.最小值为0data = tool.fit_transform(values) #标准化,注意这里的values是array ```
-
实现方法:
3. 应用操作数据
df_Score = pd.read_csv("cj.txt",sep="\t")
df_Score
学号 | 班级 | 姓名 | 性别 | 英语 | 体育 | 军训 | 数分 | 高代 | 解几 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 2308024241 | 23080242 | 成龙 | 男 | 76 | 78 | 77 | 40 | 23 | 60 |
1 | 2308024244 | 23080242 | 周怡 | 女 | 66 | 91 | 75 | 47 | 47 | 44 |
2 | 2308024251 | 23080242 | 张波 | 男 | 85 | 81 | 75 | 45 | 45 | 60 |
3 | 2308024249 | 23080242 | 朱浩 | 男 | 65 | 50 | 80 | 72 | 62 | 71 |
4 | 2308024219 | 23080242 | 封印 | 女 | 73 | 88 | 92 | 61 | 47 | 46 |
5 | 2308024201 | 23080242 | 迟培 | 男 | 60 | 50 | 89 | 71 | 76 | 71 |
6 | 2308024347 | 23080243 | 李华 | 女 | 67 | 61 | 84 | 61 | 65 | 78 |
7 | 2308024307 | 23080243 | 陈田 | 男 | 76 | 79 | 86 | 69 | 40 | 69 |
8 | 2308024326 | 23080243 | 余皓 | 男 | 66 | 67 | 85 | 65 | 61 | 71 |
9 | 2308024320 | 23080243 | 李嘉 | 女 | 62 | 60 | 90 | 60 | 67 | 77 |
10 | 2308024342 | 23080243 | 李上初 | 男 | 76 | 90 | 84 | 60 | 66 | 60 |
11 | 2308024310 | 23080243 | 郭窦 | 女 | 79 | 67 | 84 | 64 | 64 | 79 |
12 | 2308024435 | 23080244 | 姜毅涛 | 男 | 77 | 71 | 65 | 61 | 73 | 76 |
13 | 2308024432 | 23080244 | 赵宇 | 男 | 74 | 74 | 88 | 68 | 70 | 71 |
14 | 2308024446 | 23080244 | 周路 | 女 | 76 | 80 | 77 | 61 | 74 | 80 |
15 | 2308024421 | 23080244 | 林建祥 | 男 | 72 | 72 | 81 | 63 | 90 | 75 |
16 | 2308024433 | 23080244 | 李大强 | 男 | 79 | 76 | 77 | 78 | 70 | 70 |
17 | 2308024428 | 23080244 | 李侧通 | 男 | 64 | 96 | 91 | 69 | 60 | 77 |
18 | 2308024402 | 23080244 | 王慧 | 女 | 73 | 74 | 93 | 70 | 71 | 75 |
19 | 2308024422 | 23080244 | 李晓亮 | 男 | 85 | 60 | 85 | 72 | 72 | 83 |
20 | 2308024201 | 23080242 | 迟培 | 男 | 60 | 50 | 89 | 71 | 76 | 71 |
# 查看数据整体信息
df_Score.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 21 entries, 0 to 20
Data columns (total 10 columns):# Column Non-Null Count Dtype
--- ------ -------------- ----- 0 学号 21 non-null int64 1 班级 21 non-null int64 2 姓名 21 non-null object3 性别 21 non-null object4 英语 21 non-null int64 5 体育 21 non-null int64 6 军训 21 non-null int64 7 数分 21 non-null int64 8 高代 21 non-null int64 9 解几 21 non-null int64
dtypes: int64(8), object(2)
memory usage: 1.8+ KB
调用自定义函数进行Min-Max标准化
# 获取英语成绩
score_English = df_Score["英语"]
# 调用自定义Min-Max标准化函数进行标准化
scoreScaled_English1 = min_max_sca(score_English)
scoreScaled_English1
0 0.64
1 0.24
2 1.00
3 0.20
4 0.52
5 0.00
6 0.28
7 0.64
8 0.24
9 0.08
10 0.64
11 0.76
12 0.68
13 0.56
14 0.64
15 0.48
16 0.76
17 0.16
18 0.52
19 1.00
20 0.00
Name: 英语, dtype: float64
scoreScaled_English1.describe()
count 21.000000
mean 0.478095
std 0.300527
min 0.000000
25% 0.240000
50% 0.520000
75% 0.640000
max 1.000000
Name: 英语, dtype: float64
调用sklearn的MinMaxScaler进行Min-Max标准化**
from sklearn.preprocessing import MinMaxScalertool = MinMaxScaler(feature_range=(0, 1)) #根据需要设置最大最小值,这里设置最大值为1.最小值为0
values = df_Score.loc[:,"英语":"解几"].values
scoresScaled = tool.fit_transform(values)
scoresScaled
array([[0.64 , 0.60869565, 0.42857143, 0. , 0. ,0.41025641],[0.24 , 0.89130435, 0.35714286, 0.18421053, 0.35820896,0. ],[1. , 0.67391304, 0.35714286, 0.13157895, 0.32835821,0.41025641],[0.2 , 0. , 0.53571429, 0.84210526, 0.58208955,0.69230769],[0.52 , 0.82608696, 0.96428571, 0.55263158, 0.35820896,0.05128205],[0. , 0. , 0.85714286, 0.81578947, 0.79104478,0.69230769],[0.28 , 0.23913043, 0.67857143, 0.55263158, 0.62686567,0.87179487],[0.64 , 0.63043478, 0.75 , 0.76315789, 0.25373134,0.64102564],[0.24 , 0.36956522, 0.71428571, 0.65789474, 0.56716418,0.69230769],[0.08 , 0.2173913 , 0.89285714, 0.52631579, 0.65671642,0.84615385],[0.64 , 0.86956522, 0.67857143, 0.52631579, 0.64179104,0.41025641],[0.76 , 0.36956522, 0.67857143, 0.63157895, 0.6119403 ,0.8974359 ],[0.68 , 0.45652174, 0. , 0.55263158, 0.74626866,0.82051282],[0.56 , 0.52173913, 0.82142857, 0.73684211, 0.70149254,0.69230769],[0.64 , 0.65217391, 0.42857143, 0.55263158, 0.76119403,0.92307692],[0.48 , 0.47826087, 0.57142857, 0.60526316, 1. ,0.79487179],[0.76 , 0.56521739, 0.42857143, 1. , 0.70149254,0.66666667],[0.16 , 1. , 0.92857143, 0.76315789, 0.55223881,0.84615385],[0.52 , 0.52173913, 1. , 0.78947368, 0.71641791,0.79487179],[1. , 0.2173913 , 0.71428571, 0.84210526, 0.73134328,1. ],[0. , 0. , 0.85714286, 0.81578947, 0.79104478,0.69230769]])
scoresScaled_English2=scoresScaled[:,0]
scoresScaled_English2
array([0.64, 0.24, 1. , 0.2 , 0.52, 0. , 0.28, 0.64, 0.24, 0.08, 0.64,0.76, 0.68, 0.56, 0.64, 0.48, 0.76, 0.16, 0.52, 1. , 0. ])
# 均值
scoresScaled_English2.mean()
0.47809523809523813
# 标准差
scoresScaled_English2.std()
0.29328385482520825
# 最小值
scoresScaled_English2.min()
0.0
# 最大值
scoresScaled_English2.max()
1.0
6.2.2.2 均值标准化(Z-Score Normalization)
-
计算公式:
z = x − μ σ z=\frac{x-\mu}{\sigma} z=σx−μ
-
特点:
- 标准化之后的数据不仅局限于[0,1],可以为正的,也可以为负的,总之,均值为0,标准差为1
- 不会影响数据的整体分布,大的值转化之后还是较大的,小的值转化之后还是较小的
-
实现方法:
- 自定义函数方式
def stand_sca(data):"""标准差标准化数据:param data: series/datafrmae:return: 标准化之后的数据"""data = (data - data.mean()) / data.std()return data
-
实现方法:
2. sklearn的StandardScaler方法from sklearn.preprocessing import StandardScalerss=StandardScaler()Xtrain_data=ss.fit_transform(train_data) #标准化训练集然后保存训练集的均值和方差Xtest_data=ss.transform(test_data) #转换测试集数据print(ss.mean_)print(ss.var_)
-
实现方法:
3. 应用操作数据
# df_Score #查看上面读取出的数据
scores = df_Score.iloc[:,4:10]
scores.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 21 entries, 0 to 20
Data columns (total 6 columns):# Column Non-Null Count Dtype
--- ------ -------------- -----0 英语 21 non-null int641 体育 21 non-null int642 军训 21 non-null int643 数分 21 non-null int644 高代 21 non-null int645 解几 21 non-null int64
dtypes: int64(6)
memory usage: 1.1 KB
# 调用自定义函数进行标准化
stand_sca(scores.values)
array([[ 0.43438518, 0.59257169, 0.51347844, -2.41297202, -3.75755737,-0.83110691],[-0.35654737, 1.62078402, 0.35529193, -1.85931923, -1.85931923,-2.096599 ],[ 1.14622448, 0.82985146, 0.35529193, -2.01750575, -2.01750575,-0.83110691],[-0.43564063, -1.62203947, 0.75075821, 0.11801216, -0.6729204 ,0.0389189 ],[ 0.19710542, 1.38350425, 1.69987727, -0.75201365, -1.85931923,-1.93841249],[-0.83110691, -1.62203947, 1.46259751, 0.0389189 , 0.43438518,0.0389189 ],[-0.27745412, -0.75201365, 1.06713123, -0.75201365, -0.43564063,0.59257169],[ 0.43438518, 0.67166495, 1.22531774, -0.11926761, -2.41297202,-0.11926761],[-0.35654737, -0.27745412, 1.14622448, -0.43564063, -0.75201365,0.0389189 ],[-0.6729204 , -0.83110691, 1.54169076, -0.83110691, -0.27745412,0.51347844],[ 0.43438518, 1.54169076, 1.06713123, -0.83110691, -0.35654737,-0.83110691],[ 0.67166495, -0.27745412, 1.06713123, -0.51473389, -0.51473389,0.67166495],[ 0.51347844, 0.0389189 , -0.43564063, -0.75201365, 0.19710542,0.43438518],[ 0.27619867, 0.27619867, 1.38350425, -0.19836086, -0.04017435,0.0389189 ],[ 0.43438518, 0.75075821, 0.51347844, -0.75201365, 0.27619867,0.75075821],[ 0.11801216, 0.11801216, 0.82985146, -0.59382714, 1.54169076,0.35529193],[ 0.67166495, 0.43438518, 0.51347844, 0.59257169, -0.04017435,-0.04017435],[-0.51473389, 2.0162503 , 1.62078402, -0.11926761, -0.83110691,0.51347844],[ 0.19710542, 0.27619867, 1.77897053, -0.04017435, 0.0389189 ,0.35529193],[ 1.14622448, -0.83110691, 1.14622448, 0.11801216, 0.11801216,0.98803797],[-0.83110691, -1.62203947, 1.46259751, 0.0389189 , 0.43438518,0.0389189 ]])
# 调用sklearn库预处理函数
from sklearn.preprocessing import StandardScalerss=StandardScaler()
scores_scaled=ss.fit_transform(scores)
scores_scaled
array([[ 0.55204117, 0.44230299, -0.90469951, -2.50457384, -2.7077287 ,-0.95911099],[-0.81182525, 1.42399987, -1.19698705, -1.75012229, -1.0753181 ,-2.53882322],[ 1.77952094, 0.66884842, -1.19698705, -1.96567988, -1.21135231,-0.95911099],[-0.94821189, -1.67212106, -0.46626821, 0.94434751, -0.05506147,0.12694116],[ 0.14288124, 1.19745443, 1.287457 , -0.2412192 , -1.0753181 ,-2.34135919],[-1.6301451 , -1.67212106, 0.8490257 , 0.83656872, 0.89717805,0.12694116],[-0.67543861, -0.84145447, 0.11830686, -0.2412192 , 0.14898986,0.81806526],[ 0.55204117, 0.51781813, 0.41059439, 0.62101114, -1.55143786,-0.07052287],[-0.81182525, -0.3883636 , 0.26445063, 0.18989597, -0.12307858,0.12694116],[-1.35737181, -0.91696961, 0.99516946, -0.34899799, 0.28502407,0.71933325],[ 0.55204117, 1.34848472, 0.11830686, -0.34899799, 0.21700697,-0.95911099],[ 0.96120109, -0.3883636 , 0.11830686, 0.08211717, 0.08097275,0.91679727],[ 0.68842781, -0.08630302, -2.65842472, -0.2412192 , 0.69312673,0.62060123],[ 0.27926789, 0.14024241, 0.70288193, 0.51323234, 0.4890754 ,0.12694116],[ 0.55204117, 0.59333328, -0.90469951, -0.2412192 , 0.76114383,1.01552929],[ 0.0064946 , -0.01078788, -0.32012444, -0.02566162, 1.84941757,0.52186922],[ 0.96120109, 0.2912727 , -0.90469951, 1.59102027, 0.4890754 ,0.02820915],[-1.08459853, 1.80157559, 1.14131323, 0.62101114, -0.19109569,0.71933325],[ 0.14288124, 0.14024241, 1.43360077, 0.72878993, 0.55709251,0.52186922],[ 1.77952094, -0.91696961, 0.26445063, 0.94434751, 0.62510962,1.31172533],[-1.6301451 , -1.67212106, 0.8490257 , 0.83656872, 0.89717805,0.12694116]])
print(ss.mean_)
print(ss.var_)
[71.95238095 72.14285714 83.19047619 63.23809524 62.80952381 69.71428571]
[ 53.75963719 175.36054422 46.82086168 86.0861678 216.15419501102.58503401]
# 转换前数据统计信息
scores.describe()
英语 | 体育 | 军训 | 数分 | 高代 | 解几 | |
---|---|---|---|---|---|---|
count | 21.000000 | 21.000000 | 21.000000 | 21.000000 | 21.000000 | 21.000000 |
mean | 71.952381 | 72.142857 | 83.190476 | 63.238095 | 62.809524 | 69.714286 |
std | 7.513163 | 13.569398 | 7.011555 | 9.507391 | 15.065255 | 10.378549 |
min | 60.000000 | 50.000000 | 65.000000 | 40.000000 | 23.000000 | 44.000000 |
25% | 66.000000 | 61.000000 | 77.000000 | 61.000000 | 60.000000 | 69.000000 |
50% | 73.000000 | 74.000000 | 84.000000 | 64.000000 | 66.000000 | 71.000000 |
75% | 76.000000 | 80.000000 | 89.000000 | 70.000000 | 72.000000 | 77.000000 |
max | 85.000000 | 96.000000 | 93.000000 | 78.000000 | 90.000000 | 83.000000 |
# 转换后数据均值
scores_scaled.mean(axis=0)
array([ 4.75809868e-16, 3.06633026e-16, 1.21595855e-16, -2.85485921e-16,-3.70074342e-17, 6.06657581e-16])
# 转换后数据标准差
scores_scaled.std(axis=0)
array([1., 1., 1., 1., 1., 1.])
6.2.2.3 小数定标标准化
-
通过移动小数点的位置来进行数据转化,将数据转化为[-1,1]之间
-
小数点移动的位数 取决于该列数据绝对值的最大值
-
计算公式:
X ∗ = X 1 0 k X^{*}=\frac{X}{10^{k}} X∗=10kX
-
实现方法:
# 实现小数定标标准化
def desc_sca(data):"""小数定标标准化:param data: series/dataframe:return: 标准化之后的数据"""# abs() --取绝对值# np.ceil --向上取整data = data / (10 ** (int(np.ceil(np.log10(data.abs().max())))))return data
# 查看前面的数据库
#scores
scores_scaled3 = desc_sca(scores.loc[:,"英语"])
#scores_scaled3
scores_scaled3
0 0.76
1 0.66
2 0.85
3 0.65
4 0.73
5 0.60
6 0.67
7 0.76
8 0.66
9 0.62
10 0.76
11 0.79
12 0.77
13 0.74
14 0.76
15 0.72
16 0.79
17 0.64
18 0.73
19 0.85
20 0.60
Name: 英语, dtype: float64
6.2.3 Pandas数据离散化处理操作
某些模型算法,要求数据是离散的,此时就需要将连续型特征(数值型)变换成离散型特征(类别型)。
连续特征的离散化就是在数据的取值范围内设定若干个离散的划分点,将取值范围划分为一些离散化的区间,最后用不同的符号或整数值代表落在每个子区间中的数据值。
因此离散化涉及两个子任务,即确定分类数以及如何将连续型数据映射到这些类别型数据上。
离散化处理的必要性:
- 节约计算资源,提高计算效率。
- 算法模型(尤其是分类模型)的计算需要。虽然很多模型,例如决策树可以支持输入连续型数据,但是决策树本身会先将连续型数据转化为离散型数据,因此离散化转换是一个必要步骤。
- 增强模型的稳定性和准确度。数据离散化之后,处于异常状态的数据不会明显突出异常特征,而是会被划分为一个子集中的一部分,因此异常数据对模型的影响会大大降低,尤其是基于距离计算的模型(例如K均值、协同过滤等)效果明显。
- 特定数据处理和分析的必要步骤,尤其在图像处理方面应用广泛。大多数图像做特征检测(以及其他基于特征的分析)时,都需要先将图像做二值化处理,二值化也是离散化的一种。
- 模型结果应用和部署的需要。如果原始数据的值域分布过多,或值域划分不符合业务逻辑,那么模型结果将很难被业务理解并应用。
6.2.3.1 时间数据的离散化
时间数据的离散化主要用于以时间为主要特征的数据集中和粒
度转换,离散化处理后将分散的时间特征转换为更高层次的时间特征。
在带有时间的数据集中,时间可能作为行记录的序列,也可能作为
列(维度)记录数据特征。常见的针对时间数据的离散化操作分为两
类:
- 针对一天中的时间离散化。一般是将时间戳转换为秒、分钟、小
时或上下午。 - 针对日粒度以上数据的离散化。一般是将日期转化为周数、周
几、月、工作日或休息日、季度、年等。
针对时间数据的离散化可以将细粒度的时间序列数据离散化为粗粒
度的三类数据:
- 离散化为分类数据,例如上午、下午;
- 离散化为顺序数据,例如周一、周二、周三;
- 离散化为数值型数据,例如一年有52个周,周数是数值型数据。
import pandas as pd
from sklearn import preprocessing# 读取数据
df = pd.read_table('data7.txt', names=['id', 'amount', 'income', 'datetime', 'age']) # 读取数据文件
print (df.head(5)) # 打印输出前5条数据
id amount income datetime age
0 15093 1390 10.40 2017-04-30 19:24:13 0-10
1 15062 4024 4.68 2017-04-27 22:44:59 70-80
2 15028 6359 3.84 2017-04-27 10:07:55 40-50
3 15012 7759 3.70 2017-04-04 07:28:18 30-40
4 15021 331 4.25 2017-04-08 11:14:00 70-80
将datetime数据离散化为星期几
- 方法 1 :使用 pd.to_datetime 及 dt.dayofweek
# 将数据转成 datetime 类型
df['datetime'] = pd.to_datetime(df['datetime'])# 显示 周几
df['dow'] = df['datetime'].dt.dayofweek# 查看前5行
df.head()
id | amount | income | datetime | age | dow | |
---|---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 2017-04-30 19:24:13 | 0-10 | 6 |
1 | 15062 | 4024 | 4.68 | 2017-04-27 22:44:59 | 70-80 | 3 |
2 | 15028 | 6359 | 3.84 | 2017-04-27 10:07:55 | 40-50 | 3 |
3 | 15012 | 7759 | 3.70 | 2017-04-04 07:28:18 | 30-40 | 1 |
4 | 15021 | 331 | 4.25 | 2017-04-08 11:14:00 | 70-80 | 5 |
- 方法 2:纯手工打造
# 将时间转换为datetime格式,Python3中,map返回一个迭代器,所以需要list一下,把其中的值取出来
df['datetime'] = list(map(pd.to_datetime,df['datetime']))
# 离散化为 周几 的格式
df['datetime']= [i.weekday() for i in df['datetime']]# 查看前5行
df.head()
id | amount | income | datetime | age | dow | |
---|---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 6 | 0-10 | 6 |
1 | 15062 | 4024 | 4.68 | 3 | 70-80 | 3 |
2 | 15028 | 6359 | 3.84 | 3 | 40-50 | 3 |
3 | 15012 | 7759 | 3.70 | 1 | 30-40 | 1 |
4 | 15021 | 331 | 4.25 | 5 | 70-80 | 5 |
6.2.3.2 连续数据的离散化
连续数据的离散化结果可以分为两类:
-
一类是将连续数据划分为特定区间的集合,例如{(0,10],(10,20],(20,50],(50,100]}
-
一类是将连续数据划分为特定类,例如类1、类2、类3
常见实现针对连续数据化离散化的方法如下:
-
分位数法:使用四分位、五分位、十分位等分位数进行离散化处理
-
距离区间法:可使用等距区间或自定义区间的方式进行离散化,该方法(尤其是等距区间)可以较好地保持数据原有的分布
-
频率区间法:将数据按照不同数据的频率分布进行排序,然后按照等频率或指定频率离散化,这种方法会把数据变换成均匀分布。好处是各区间的观察值是相同的,不足会改变了原有数据的分布状态。每个桶里的数值个数是相同的
-
聚类法:例如使用 K 均值将样本集分为多个离散化的簇
6.2.3.2.1 距离区间法:自定义分箱区间实现离散化
使用pd.cut进行分箱。
- pd.cut()基本语法:
pandas.cut(x,bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False, duplicates='raise')
-
pd.cut()参数说明:
-
x:被切分的类数组(array-like)数据,必须是1维的(不能用DataFrame);
-
bins:bins是被切割后的区间(或者叫“桶”、“箱”、“面元”),有3中形式:一个int型的标量、标量序列(数组)或者pandas.IntervalIndex 。
- 一个int型的标量
当bins为一个int型的标量时,代表将x平分成bins份。x的范围在每侧扩展0.1%,以包括x的最大值和最小值。 - 标量序列
标量序列定义了被分割后每一个bin的区间边缘,此时x没有扩展。 - pandas.IntervalIndex
定义要使用的精确区间。
- 一个int型的标量
-
right:bool型参数,默认为True,表示是否包含区间右部。比如如果bins=[1,2,3],right=True,则区间为(1,2],(2,3];right=False,则区间为(1,2),(2,3)。
-
labels:给分割后的bins打标签,比如把年龄x分割成年龄段bins后,可以给年龄段打上诸如青年、中年的标签。labels的长度必须和划分后的区间长度相等,比如bins=[1,2,3],划分后有2个区间(1,2],(2,3],则labels的长度必须为2。如果指定
-
labels=False,则返回x中的数据在第几个bin中(从0开始)。
-
retbins:bool型的参数,表示是否将分割后的bins返回,当bins为一个int型的标量时比较有用,这样可以得到划分后的区间,默认为False。
-
precision:保留区间小数点的位数,默认为3.
-
include_lowest:bool型的参数,表示区间的左边是开还是闭的,默认为false,也就是不包含区间左部(闭)。
-
duplicates:是否允许重复区间。有两种选择:raise:不允许,drop:允许。
-
-
返回值:
- out:一个pandas.Categorical, Series或者ndarray类型的值,代表分区后x中的每个值在哪个bin(区间)中,如果指定了labels,则返回对应的label。
- bins:分隔后的区间,当指定retbins为True时返回。
df.head(3)
id | amount | income | datetime | age | dow | |
---|---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 6 | 0-10 | 6 |
1 | 15062 | 4024 | 4.68 | 3 | 70-80 | 3 |
2 | 15028 | 6359 | 3.84 | 3 | 40-50 | 3 |
将amount离散化
# 自定义区间边界
bins = [0, 200, 1000, 5000, 10000]
# 按照给定区间 使用 pd.cut 将数据进行离散化
df['amount_grp1'] = pd.cut(df['amount'], bins=bins)
df.head()
id | amount | income | datetime | age | dow | amount_grp1 | |
---|---|---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 6 | 0-10 | 6 | (1000, 5000] |
1 | 15062 | 4024 | 4.68 | 3 | 70-80 | 3 | (1000, 5000] |
2 | 15028 | 6359 | 3.84 | 3 | 40-50 | 3 | (5000, 10000] |
3 | 15012 | 7759 | 3.70 | 1 | 30-40 | 1 | (5000, 10000] |
4 | 15021 | 331 | 4.25 | 5 | 70-80 | 5 | (200, 1000] |
# bins传递整数标量
# 按照给定区间 使用 pd.cut 将数据进行离散化
df['amount_grp2'] = pd.cut(df['amount'], bins=10)
df.head()
id | amount | income | datetime | age | dow | amount_grp1 | amount_grp2 | |
---|---|---|---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 6 | 0-10 | 6 | (1000, 5000] | (953.6, 1731.2] |
1 | 15062 | 4024 | 4.68 | 3 | 70-80 | 3 | (1000, 5000] | (3286.4, 4064.0] |
2 | 15028 | 6359 | 3.84 | 3 | 40-50 | 3 | (5000, 10000] | (5619.2, 6396.8] |
3 | 15012 | 7759 | 3.70 | 1 | 30-40 | 1 | (5000, 10000] | (7174.4, 7952.0] |
4 | 15021 | 331 | 4.25 | 5 | 70-80 | 5 | (200, 1000] | (168.224, 953.6] |
# 实现离散化 并添加自定义标签
bins = [0, 200, 1000, 5000, 10000]
labels = [ '<200', '200~1000','1000~5000','5000~10000']
# 按照给定区间 使用 pd.cut 将数据进行离散化
# right == False : 左闭右开,不加此项,默认为左开右闭的
df['amount_level'] = pd.cut(df.amount, bins=bins,labels=labels,right=False)
df.head()
id | amount | income | datetime | age | dow | amount_grp1 | amount_grp2 | amount_level | |
---|---|---|---|---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 6 | 0-10 | 6 | (1000, 5000] | (953.6, 1731.2] | 1000~5000 |
1 | 15062 | 4024 | 4.68 | 3 | 70-80 | 3 | (1000, 5000] | (3286.4, 4064.0] | 1000~5000 |
2 | 15028 | 6359 | 3.84 | 3 | 40-50 | 3 | (5000, 10000] | (5619.2, 6396.8] | 5000~10000 |
3 | 15012 | 7759 | 3.70 | 1 | 30-40 | 1 | (5000, 10000] | (7174.4, 7952.0] | 5000~10000 |
4 | 15021 | 331 | 4.25 | 5 | 70-80 | 5 | (200, 1000] | (168.224, 953.6] | 200~1000 |
6.2.3.2.2 频率区间法:按照等频率或指定频率离散化
使用pd.qcut()函数进行处理。
- pd.qcut()基本语法:
pandas.qcut(x, q,labels=None, retbins=False, precision=3, duplicates='raise')
-
pd.qcut()参数说明:
-
x :一维数组或者Serise
-
q : 表示分位数的整数或者数组,
- 如果是分位数的整数,例如10用于十分位,4用于四分位
- 如果是分位数数组,例如[0,0.25,0.5,0.75,1]用于四分位数
-
labels : 数组或者布尔值,默认为none,用于指定每个箱体的标签
- 如果是数组,长度要与分箱个数一致,比如用四分位数分箱,需要指定四个标签
- 如果为False,则仅返回分箱的整数指示符,即当前数据位于哪个箱子中
-
rebines :布尔值,可选。 是否显示分箱的分界值。(由于是按照分位数进行分箱,在不知道分位数具体数值的情况下,可以通过这个参数设置显示分界值即分位数的具体数值)
-
precision:整数,默认3,存储和显示分箱标签的精度。
-
duplicates:如果分箱临界值不唯一,则引发ValueError或丢弃非唯一
-
-
返回值:
- out:一个pandas.Categorical, Series或者ndarray类型的值,代表分区后x中的每个值在哪个bin(区间)中,如果指定了labels,则返回对应的label。
- bins:分隔后的区间,当指定retbins为True时返回。
df.head()
id | amount | income | datetime | age | dow | amount_grp1 | amount_grp2 | amount_level | |
---|---|---|---|---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 6 | 0-10 | 6 | (1000, 5000] | (953.6, 1731.2] | 1000~5000 |
1 | 15062 | 4024 | 4.68 | 3 | 70-80 | 3 | (1000, 5000] | (3286.4, 4064.0] | 1000~5000 |
2 | 15028 | 6359 | 3.84 | 3 | 40-50 | 3 | (5000, 10000] | (5619.2, 6396.8] | 5000~10000 |
3 | 15012 | 7759 | 3.70 | 1 | 30-40 | 1 | (5000, 10000] | (7174.4, 7952.0] | 5000~10000 |
4 | 15021 | 331 | 4.25 | 5 | 70-80 | 5 | (200, 1000] | (168.224, 953.6] | 200~1000 |
df['amount_grp3'] = pd.qcut(df['amount'], 4, labels=['bad', 'medium', 'good', 'awesome'])
df.head()
id | amount | income | datetime | age | dow | amount_grp1 | amount_grp2 | amount_level | amount_grp3 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 6 | 0-10 | 6 | (1000, 5000] | (953.6, 1731.2] | 1000~5000 | bad |
1 | 15062 | 4024 | 4.68 | 3 | 70-80 | 3 | (1000, 5000] | (3286.4, 4064.0] | 1000~5000 | good |
2 | 15028 | 6359 | 3.84 | 3 | 40-50 | 3 | (5000, 10000] | (5619.2, 6396.8] | 5000~10000 | awesome |
3 | 15012 | 7759 | 3.70 | 1 | 30-40 | 1 | (5000, 10000] | (7174.4, 7952.0] | 5000~10000 | awesome |
4 | 15021 | 331 | 4.25 | 5 | 70-80 | 5 | (200, 1000] | (168.224, 953.6] | 200~1000 | bad |
6.2.3.2.3 聚类法实现离散化
sklearn中的KMeans详细介绍见知乎上的机器学习之SKlearn(scikit-learn)的K-means聚类算法
from sklearn.cluster import KMeans# 获取要聚类的数据
df_clu = df[['amount']]# 创建 KMeans 模型并指定要聚类数量
model_kmeans = KMeans(n_clusters=4, random_state=111)# 建模聚类
kmeans_result = model_kmeans.fit_predict(df_clu)# 将新离散化的数据合并到原数据框
df['amount_grp4'] = kmeans_resultdf.head()
id | amount | income | datetime | age | dow | amount_grp1 | amount_grp2 | amount_level | amount_grp3 | amount_grp4 | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 6 | 0-10 | 6 | (1000, 5000] | (953.6, 1731.2] | 1000~5000 | bad | 2 |
1 | 15062 | 4024 | 4.68 | 3 | 70-80 | 3 | (1000, 5000] | (3286.4, 4064.0] | 1000~5000 | good | 0 |
2 | 15028 | 6359 | 3.84 | 3 | 40-50 | 3 | (5000, 10000] | (5619.2, 6396.8] | 5000~10000 | awesome | 1 |
3 | 15012 | 7759 | 3.70 | 1 | 30-40 | 1 | (5000, 10000] | (7174.4, 7952.0] | 5000~10000 | awesome | 1 |
4 | 15021 | 331 | 4.25 | 5 | 70-80 | 5 | (200, 1000] | (168.224, 953.6] | 200~1000 | bad | 2 |
6.2.4 Pandas数据泛化处理操作
数据泛化:把较低层次的概念层(例如:年龄的数值范围)用较高层次的概念(例如:青年、中年和 老年)替换来汇总数据。或者通过减少维度在设计较少维度的概念空间汇总数据(例如汇总学生组群时,删除生日和电话号码属性)
数据泛化处理的常用方法也一般是数据离散化处理方法。
更多推荐
第6章 数据集成、变换与规约1
发布评论