您的位置:首页 > 编程语言 > Python开发

第3章 Pandas数据处理(3.7-3.8)_Python数据科学手册学习笔记

2018-10-16 10:34 886 查看

3.7 合并数据集: Concat与Append操作

- pd.concat
- pd.merge
- pd.join
import pandas as pd
def make_df(cols,ind):
data = {c: [str(c) + str(i) for i in ind]
for c in cols}
return pd.DataFrame(data,ind)     # 用字典创建DataFrame
make_df('ABC',range(3))
A B C
0 A0 B0 C0
1 A1 B1 C1
2 A2 B2 C2

3.7.1 知识回顾: NumPy数组的合并

用np.concatenate完成
- 第一个参数表示要合并的数组或元组, 第二个参数表示合并的坐标轴方向

import pandas as pd
import numpy as np
x = [1,2,3]
y = [4,5,6]
z = [7,8,9]
np.concatenate([x,y,z])
array([1, 2, 3, 4, 5, 6, 7, 8, 9])
x = [[1,2],
[3,4]]
np.concatenate([x,x], axis=1)
array([[1, 2, 1, 2],
[3, 4, 3, 4]])

3.7.2 通过pd.concat实现简易合并

- Pandas中的pd.concat()函数与np.concatenate()类似, 配置参数更多,功能更强大.

pd.concat()可以简单的合并一维的Series和DataFrame对象

ser1 = pd.Series(['a','b','c'],index=[1,2,3])
ser2 = pd.Series(['d','e','f'],index=[4,5,6])
pd.concat([ser1,ser2])
1    a
2    b
3    c
4    d
5    e
6    f
dtype: object
ser1 = pd.Series(['a','b','c'],index=[1,2,3])
ser2 = pd.Series(['d','e','f'],index=[4,5,6])
ser1 + ser2
1    NaN
2    NaN
3    NaN
4    NaN
5    NaN
6    NaN
dtype: object
ser1 = pd.Series(['a','b','c'],index=[1,2,3])
ser2 = pd.Series(['d','e','f'],index=[1,2,3])
ser1 + ser2
1    ad
2    be
3    cf
dtype: object
df1 = make_df('AB',[1,2])
df2 = make_df('AB',[3,4])
print(df1);print(df2);print(pd.concat([df1,df2]))
A   B
1  A1  B1
2  A2  B2
A   B
3  A3  B3
4  A4  B4
A   B
1  A1  B1
2  A2  B2
3  A3  B3
4  A4  B4
df1 = make_df('AB',[1,2])
df2 = make_df('BD',[3,4])
print(df1);print(df2);print(pd.concat([df1,df2]))
A   B
1  A1  B1
2  A2  B2
B   D
3  B3  D3
4  B4  D4
A   B    D
1   A1  B1  NaN
2   A2  B2  NaN
3  NaN  B3   D3
4  NaN  B4   D4

D:\Anaconda3\lib\site-packages\ipykernel_launcher.py:3: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version
of pandas will change to not sort by default.

To accept the future behavior, pass 'sort=True'.

To retain the current behavior and silence the warning, pass sort=False

This is separate from the ipykernel package so we can avoid doing imports until

索引重叠

np.concatenate与pd.concat最主要的差异是,Pandas在合并时会保留索引, 即使索引是重复的.

x = make_df('AB',[0,1])
y = make_df('AB',[2,3])
y.index = x.index
print(x);print(y);print(pd.concat([x,y]))
A   B
0  A0  B0
1  A1  B1
A   B
0  A2  B2
1  A3  B3
A   B
0  A0  B0
1  A1  B1
0  A2  B2
1  A3  B3

捕捉索引重复的错误: 可以设置verify_integrity参数. 将参数设置为true. 合并时若有重复就会触发异常.

try:
pd.concat([x,y],verify_integrity=True)
except ValueError as e:
print('ValueError:',e)
ValueError: Indexes have overlapping values: Int64Index([0, 1], dtype='int64')

忽略索引: 设置ignore_index参数, 设置为True是会创建一个新的整数索引

pd.concat([x,y],ignore_index=True)
A B
0 A0 B0
1 A1 B1
2 A2 B2
3 A3 B3

增加多级索引: 通过keys参数为数据源设置多级索引

print(x);print(y);print(pd.concat([x,y],keys=['x','y']))
A   B
0  A0  B0
1  A1  B1
A   B
0  A2  B2
1  A3  B3
A   B
x 0  A0  B0
1  A1  B1
y 0  A2  B2
1  A3  B3

类似join的合并

df5 = make_df('ABC',[1,2])
df6 = make_df('BCD',[3,4])
print(df5);print(df6);print(pd.concat([df5,df6]))
A   B   C
1  A1  B1  C1
2  A2  B2  C2
B   C   D
3  B3  C3  D3
4  B4  C4  D4
A   B   C    D
1   A1  B1  C1  NaN
2   A2  B2  C2  NaN
3  NaN  B3  C3   D3
4  NaN  B4  C4   D4

D:\Anaconda3\lib\site-packages\ipykernel_launcher.py:3: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version
of pandas will change to not sort by default.

To accept the future behavior, pass 'sort=True'.

To retain the current behavior and silence the warning, pass sort=False

This is separate from the ipykernel package so we can avoid doing imports until

设置join参数为inner或者outer

print(df5);print(df6);print(pd.concat([df5,df6],join='inner'))
A   B   C
1  A1  B1  C1
2  A2  B2  C2
B   C   D
3  B3  C3  D3
4  B4  C4  D4
B   C
1  B1  C1
2  B2  C2
3  B3  C3
4  B4  C4

直接确定结果使用的列

print(df5);print(df6);print(pd.concat([df5,df6],join_axes=[df5.columns]))
A   B   C
1  A1  B1  C1
2  A2  B2  C2
B   C   D
3  B3  C3  D3
4  B4  C4  D4
A   B   C
1   A1  B1  C1
2   A2  B2  C2
3  NaN  B3  C3
4  NaN  B4  C4
print(df1);print(df2);print(df1.append(df2))
A   B
1  A1  B1
2  A2  B2
A   B
3  A3  B3
4  A4  B4
A   B
1  A1  B1
2  A2  B2
3  A3  B3
4  A4  B4

3.8 合并数据集: 合并与连接

- Pandas的主要接口是pd.merge()函数

3.8.1 关系代数

pd.merge()实现的功能基于关系代数的一部分. 关系代数式处理关系型数据的通用理论,绝大部分数据库的可用操作都以此为理论基础. 关系代数方法论的强大之处在于, 它提出的若干简单的操作规则经过组合就可以为任意数据构建十分复杂的操作.
Pandas在pd.merge()函数与Series和DataFrame的join()方法里实现了这些基本操作规则.

3.8.2 数据连接的类型

pd.merge()函数实现三种数据连接的类型: 一对一,多对一和多对多.

** 一对一连接 **

import pandas as pd
df1 = pd.DataFrame({'雇员':['张三','李四','王五','赵六'],'部门':['生产','技术','技术','人力']})   # 需要加大括号
df2 = pd.DataFrame({'雇员':['赵六','李四','张三','王五'],'入职年份':[2010,2011,2012,2011]})
print(df1);print(df2)
雇员  部门
0  张三  生产
1  李四  技术
2  王五  技术
3  赵六  人力
雇员  入职年份
0  赵六  2010
1  李四  2011
2  张三  2012
3  王五  2011
df3 = pd.merge(df1,df2)
print(df3)
雇员  部门  入职年份
0  张三  生产  2012
1  李四  技术  2011
2  王五  技术  2011
3  赵六  人力  2010

pd.merge()方法会发现两个DataFrame都有’雇员’列, 并自动以这列为键进行连接. 两个输入的合并结果是一个新的DataFrame. 共同列的位置可以不一致.
pd.merge()会默认丢弃原来的行索引, 不过也可以自定义.

多对一连接 能否也叫一对多连接

需要连接的两个列中, 有一列的值有重复. 通过多对一连接获得的结果DataFrame将会保留重复值.

df4 = pd.DataFrame({'部门':['生产','技术','人力'],'负责人':['生产经理','技术经理','人力经理']})
print(df3);print(df4);print(pd.merge(df3,df4))
雇员  部门  入职年份
0  张三  生产  2012
1  李四  技术  2011
2  王五  技术  2011
3  赵六  人力  2010部门   负责人
0  生产  生产经理
1  技术  技术经理
2  人力  人力经理
雇员  部门  入职年份   负责人
0  张三  生产  2012  生产经理
1  李四  技术  2011  技术经理
2  王五  技术  2011  技术经理
3  赵六  人力  2010  人力经理

多对多连接

df5 = pd.DataFrame({'部门':['生产','生产','技术','技术','人力','人力'],'子部门':['生产1','生产2','技术1','技术2','人力1','人力2']})
print(df1);print(df5);print(pd.merge(df1,df5))
雇员  部门
0  张三  生产
1  李四  技术
2  王五  技术
3  赵六  人力
部门  子部门
0  生产  生产1
1  生产  生产2
2  技术  技术1
3  技术  技术2
4  人力  人力1
5  人力  人力2
雇员  部门  子部门
0  张三  生产  生产1
1  张三  生产  生产2
2  李四  技术  技术1
3  李四  技术  技术2
4  王五  技术  技术1
5  王五  技术  技术2
6  赵六  人力  人力1
7  赵六  人力  人力2

3.8.3 设置数据合并的键

pd.merge()的默认行为, 它会将两个输入的一个或多个共同列作为键进行合并. 但由于两个输入要合并的列通常都不是同名的, 因此pd.merge()提供了一些参数处理这个问题.

参数on的用法
- 这个参数只能在两个DataFrame有共同列名的时候才可以使用.

print(df1);print(df2);print(pd.merge(df1,df2,on='雇员'))
雇员  部门
0  张三  生产
1  李四  技术
2  王五  技术
3  赵六  人力
雇员  入职年份
0  赵六  2010
1  李四  2011
2  张三  2012
3  王五  2011雇员  部门  入职年份
0  张三  生产  2012
1  李四  技术  2011
2  王五  技术  2011
3  赵六  人力  2010

left_on与right_on参数
- 有时候也需要合并两个列名不同的数据集.

df3 = pd.DataFrame({'姓名':['张三','李四','王五','赵六'],'工资':[5000,6000,7000,5500]})
print(df1);print(df2);print(pd.merge(df1,df3,left_on='雇员',right_on='姓名'))
雇员  部门
0  张三  生产
1  李四  技术
2  王五  技术
3  赵六  人力
雇员  入职年份
0  赵六  2010
1  李四  2011
2  张三  2012
3  王五  2011雇员  部门  姓名    工资
0  张三  生产  张三  5000
1  李四  技术  李四  6000
2  王五  技术  王五  7000
3  赵六  人力  赵六  5500

汇总的结果会多一列, 可以用drop()方法去掉.

pd.merge(df1,df3,left_on='雇员',right_on='姓名').drop('姓名',axis=1)
雇员 部门 工资
0 张三 生产 5000
1 李四 技术 6000
2 王五 技术 7000
3 赵六 人力 5500

left_index与right_index参数
- 除了合并列之外, 还可以合并索引.

df1a = df1.set_index('雇员')
df2a = df2.set_index('雇员')
print(df1a);print(df2a)
部门
雇员
张三  生产
李四  技术
王五  技术
赵六  人力
入职年份
雇员
赵六  2010
李四  2011
张三  2012
王五  2011

可以通过设置pd.merge()中的left_index或right_index参数将索引设置为键来实现合并.

print(df1a);print(df2a);
print(pd.merge(df1a,df2a,left_index=True,right_index=True))  # 是True , 不是 = 索引的名称
部门
雇员
张三  生产
李四  技术
王五  技术
赵六  人力
入职年份
雇员
赵六  2010
李四  2011
张三  2012
王五  2011部门  入职年份
雇员
张三  生产  2012
李四  技术  2011
王五  技术  2011
赵六  人力  2010

为了方便考虑, DataFrame实现了join()方法, 它可以按照索引进行数据合并.

print(df1a);print(df2a);print(df1a.join(df2a))
部门
雇员
张三  生产
李四  技术
王五  技术
赵六  人力
入职年份
雇员
赵六  2010
李四  2011
张三  2012
王五  2011部门  入职年份
雇员
张三  生产  2012
李四  技术  2011
王五  技术  2011
赵六  人力  2010

如果想将索引与列混合使用, 可以使用left_index与right_on, 或者结合left_on与right_index

print(df1a);print(df3)
print(pd.merge(df1a,df3,left_index=True,right_on='姓名'))    # 多个索引怎么办
部门
雇员
张三  生产
李四  技术
王五  技术
赵六  人力
姓名    工资
0  张三  5000
1  李四  6000
2  王五  7000
3  赵六  5500
部门  姓名    工资
0  生产  张三  5000
1  技术  李四  6000
2  技术  王五  7000
3  人力  赵六  5500

3.8.4 设置数据连接的集合操作规则

df6 = pd.DataFrame({'姓名':['张三','李四','王五','赵六'],
'食物':['鱼','西瓜','冬瓜','大头菜']})
df7 = pd.DataFrame({'姓名':['张三','老李'],
'喝酒':['白酒','红酒']})
print(df6);print(df7);print(pd.merge(df6,df7))
姓名   食物
0  张三    鱼
1  李四   西瓜
2  王五   冬瓜
3  赵六  大头菜
姓名  喝酒
0  张三  白酒
1  老李  红酒
姓名 食物  喝酒
0  张三  鱼  白酒

和别的两个数据集, 在’姓名’列中只有一个共同的值’张三’. 默认情况下, 结果中只出现会包含两个输入集合的交集(inner join). 这种连接方式被称为内连接. 我们可以通过how参数设置连接方式,默认为’inner’

pd.merge(df6,df7,how='inner')
姓名 食物 喝酒
0 张三 白酒

how参数支持的连接方式: outer, left,inner 和right.
- outer(外连接)返回两个输入列的并集, 所有缺失值都用NaN填充.

print(df6);print(df7);print(pd.merge(df6,df7,how='outer'))
姓名   食物
0  张三    鱼
1  李四   西瓜
2  王五   冬瓜
3  赵六  大头菜
姓名  喝酒
0  张三  白酒
1  老李  红酒
姓名   食物   喝酒
0  张三    鱼   白酒
1  李四   西瓜  NaN
2  王五   冬瓜  NaN
3  赵六  大头菜  NaN
4  老李  NaN   红酒

left join(左连接), right join(右连接)返回的结果分别只包括左列和右列

print(df6);print(df7);print(pd.merge(df6,df7,how='left'))
姓名   食物
0  张三    鱼
1  李四   西瓜
2  王五   冬瓜
3  赵六  大头菜
姓名  喝酒
0  张三  白酒
1  老李  红酒
姓名   食物   喝酒
0  张三    鱼   白酒
1  李四   西瓜  NaN
2  王五   冬瓜  NaN
3  赵六  大头菜  NaN

3.8.5 重复列名: suffixes参数

- 可能会遇到两个输入DataFrame有重名列的情况.
df8 = pd.DataFrame({'name':['bob','jake','lisa','sue'],
'rank':[1,2,3,4]})
df9 = pd.DataFrame({'name':['bob','jake','lisa','sue'],
'rank':[3,1,4,2]})
print(df8);print(df9);print(pd.merge(df8,df9,on='name'))
name  rank
0   bob     1
1  jake     2
2  lisa     3
3   sue     4
name  rank
0   bob     3
1  jake     1
2  lisa     4
3   sue     2
name  rank_x  rank_y
0   bob       1       3
1  jake       2       1
2  lisa       3       4
3   sue       4       2

当有两个重复的列名, pd.merge()函数会自动为它们增加后缀_x _y.
也可以通过suffixes参数自定义后缀

pd.merge(df8,df9,on='name',suffixes=['_l','_r'])
name rank_l rank_r
0 bob 1 3
1 jake 2 1
2 lisa 3 4
3 sue 4 2

3.8.6 案例: 美国各州的统计数据

# 文件路径不能有中文
pop = pd.read_csv(r'E:\Python\state-population.csv')
areas = pd.read_csv(r'E:\Python\state-abbrevs.csv')
abbrevs = pd.read_csv(r'E:\Python\state-areas.csv')
print(pop.head());print(areas.head());print(abbrevs.head())
state/region     ages  year  population
0           AL  under18  2012   1117489.0
1           AL    total  2012   4817528.0
2           AL  under18  2010   1130966.0
3           AL    total  2010   4785570.0
4           AL  under18  2011   1125763.0
state abbreviation
0     Alabama           AL
1      Alaska           AK
2     Arizona           AZ
3    Arkansas           AR
4  California           CA
state  area (sq. mi)
0     Alabama          52423
1      Alaska         656425
2     Arizona         114006
3    Arkansas          53182
4  California         163707
merged = pd.merge(pop,areas,how='outer',left_on='state/region',right_on='abbreviation')
merged = merged.drop('abbreviation',1)   # 参数1不能少
print(merged.head())
state/region     ages  year  population    state
0           AL  under18  2012   1117489.0  Alabama
1           AL    total  2012   4817528.0  Alabama
2           AL  under18  2010   1130966.0  Alabama
3           AL    total  2010   4785570.0  Alabama
4           AL  under18  2011   1125763.0  Alabama

检查每个字段是否有缺失值

merged.isnull().any()
state/region    False
ages            False
year            False
population       True
state            True
dtype: bool

部分population是缺失值, 查看是哪些数据缺失值

merged[merged['population'].isnull()].head()
state/region ages year population state
2448 PR under18 1990 NaN NaN
2449 PR total 1990 NaN NaN
2450 PR total 1991 NaN NaN
2451 PR under18 1991 NaN NaN
2452 PR total 1993 NaN NaN
merged.loc[merged['state'].isnull(),'state/region'].unique()
array(['PR', 'USA'], dtype=object)
merged.loc[merged['state/region'] == 'PR','state'] = 'Puerto Rico'
merged.loc[merged['state/region'] == 'USA','state'] = 'Uinted States'
merged.isnull().any()
state/region    False
ages            False
year            False
population       True
state           False
dtype: bool
final = pd.merge(merged,abbrevs,on='state',how='left')
final.head()
state/region ages year population state area (sq. mi)
0 AL under18 2012 1117489.0 Alabama 52423.0
1 AL total 2012 4817528.0 Alabama 52423.0
2 AL under18 2010 1130966.0 Alabama 52423.0
3 AL total 2010 4785570.0 Alabama 52423.0
4 AL under18 2011 1125763.0 Alabama 52423.0
data2010 = final.query("year == 2010 & ages == 'total'")
data2010.head()
state/region ages year population state area (sq. mi)
3 AL total 2010 4785570.0 Alabama 52423.0
91 AK total 2010 713868.0 Alaska 656425.0
101 AZ total 2010 6408790.0 Arizona 114006.0
189 AR total 2010 2922280.0 Arkansas 53182.0
197 CA total 2010 37333601.0 California 163707.0
# data2010.set_index('state',inplace=True)    # 为什么报错
# density = data2010['population'] / data2010['area(sq.mi)']
# density.sort_values(ascending=False,inplace=True)
# density.head()
阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: