利用Python进行数据分析:数据规整

在许多应用中,数据可能分散在许多文件或数据库中,存储的形式也不利于分析。本部分关注可以聚合、合并、重塑数据的方法。

文章目录

  • 利用Python进行数据分析:数据规整
    • 合并数据集
      • 数据库风格的DataFrame合并
      • 索引上的合并
      • 轴向连接
      • 合并重叠数据
    • 层次化索引
      • 重排与分级排序
      • 使用DataFrame的列进行索引
    • 数据重塑
# 导入包
import pandas as pd
import numpy as np

合并数据集

pandas对象中的数据可以通过一些方式进行合并:

  • pandas.merge可根据一个或多个键将不同DataFrame中的行连接起来。其实现的就是数据库的join操作。
  • pandas.concat可以沿着一条轴将多个对象堆叠到一起。
  • 实例方法combine_first可以将重复数据拼接在一起,用一个对象中的值填充另一个对象中的缺失值。

数据库风格的DataFrame合并

df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],'data1': range(7)})
df2 = pd.DataFrame({'key': ['a', 'b', 'd'],'data2': range(3)})
df1
key data1
0 b 0
1 b 1
2 a 2
3 c 3
4 a 4
5 a 5
6 b 6
df2
key data2
0 a 0
1 b 1
2 d 2

通过on=指定用哪个列进行连接:

pd.merge(df1, df2, on='key')
key data1 data2
0 b 0 1
1 b 1 1
2 b 6 1
3 a 2 0
4 a 4 0
5 a 5 0

如果两个对象的列名不同,可以分别指定:

df1 = pd.DataFrame({'key1': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],'data1': range(7)})df2 = pd.DataFrame({'key2': ['a', 'b', 'd'],'data2': range(3)})
pd.merge(df1, df2, left_on='key1', right_on = 'key2')
key1 data1 key2 data2
0 b 0 b 1
1 b 1 b 1
2 b 6 b 1
3 a 2 a 0
4 a 4 a 0
5 a 5 a 0

默认情况下,merge做的是“内连接”;结果中的键是交集。其他方式还有"left"、“right"以及"outer”,通过`how='字段进行指定:

pd.merge(df1, df2, left_on='key1', right_on = 'key2',how = 'right')
key1 data1 key2 data2
0 a 2.0 a 0
1 a 4.0 a 0
2 a 5.0 a 0
3 b 0.0 b 1
4 b 1.0 b 1
5 b 6.0 b 1
6 NaN NaN d 2

以下列出可选的四种连接方式:

选项 说明
inner 使用两个表都有的键
left 使用左表中所有的键
right 使用右表中所有的键
outer 使用两个表中所有的键

要根据多个键进行合并,传入一个由列名组成的列表即可:

left = pd.DataFrame({'key1': ['foo', 'foo', 'bar'],'key2': ['one', 'two', 'one'],'lval': [1, 2, 3]})
 right = pd.DataFrame({'key1': ['foo', 'foo', 'bar', 'bar'],'key2': ['one', 'one', 'one', 'two'],'rval': [4, 5, 6, 7]})
pd.merge(left, right, on=['key1','key2'], how = 'outer')
key1 key2 lval rval
0 foo one 1.0 4.0
1 foo one 1.0 5.0
2 foo two 2.0 NaN
3 bar one 3.0 6.0
4 bar two NaN 7.0

待合并的对象若存在重复列名,可以通过suffixes选项指定附加到重复列名上的字符串:

pd.merge(left, right, on='key1',suffixes=('_left','_right'))
key1 key2_left lval key2_right rval
0 foo one 1 one 4
1 foo one 1 one 5
2 foo two 2 one 4
3 foo two 2 one 5
4 bar one 3 one 6
5 bar one 3 two 7

以下为merge函数的参数:


索引上的合并

上面的pd.merge方法通过right_indexleft_index参数可以用于指定将右侧或左侧的行索引用作连接键,这里不做示例。此部分介绍一个更便捷的join方法,它能更方便地实现按索引合并:

left = pd.DataFrame([[1., 2.], [3., 4.], [5., 6.]],index=['a', 'c', 'e'],columns=['Ohio', 'Nevada'])
right = pd.DataFrame([[7., 8.], [9., 10.], [11., 12.], [13, 14]],index=['b', 'c', 'd', 'e'],columns=['Missouri', 'Alabama'])
left
Ohio Nevada
a 1.0 2.0
c 3.0 4.0
e 5.0 6.0
right
Missouri Alabama
b 7.0 8.0
c 9.0 10.0
d 11.0 12.0
e 13.0 14.0

因为一些历史版本的遗留原因,DataFrame的join方法默认使用的是左连接,保留左边表的行索引:

left.join(right)
Ohio Nevada Missouri Alabama
a 1.0 2.0 NaN NaN
c 3.0 4.0 9.0 10.0
e 5.0 6.0 13.0 14.0

对于简单的索引合并,你还可以向join传入一组DataFrame:

another = pd.DataFrame([[7., 8.], [9., 10.], [11., 12.], [16., 17.]],index=['a', 'c', 'e', 'f'],columns=['New York','Oregon'])
another
New York Oregon
a 7.0 8.0
c 9.0 10.0
e 11.0 12.0
f 16.0 17.0

join支持{‘left’, ‘right’, ‘outer’, ‘inner’}四种连接方式:

left.join([right,another], how='outer')
Ohio Nevada Missouri Alabama New York Oregon
a 1.0 2.0 NaN NaN 7.0 8.0
c 3.0 4.0 9.0 10.0 9.0 10.0
e 5.0 6.0 13.0 14.0 11.0 12.0
b NaN NaN 7.0 8.0 NaN NaN
d NaN NaN 11.0 12.0 NaN NaN
f NaN NaN NaN NaN 16.0 17.0

轴向连接

假设有三个没有重叠索引的Series,pd.concat可以将值和索引堆叠在一起,默认在axis=0上工作:

s1 = pd.Series([0, 1], index=['a', 'b'])
s2 = pd.Series([2, 3, 4], index=['c', 'd', 'e'])
s3 = pd.Series([5, 6], index=['f', 'g'])
pd.concat([s1,s2,s3])
a    0
b    1
c    2
d    3
e    4
f    5
g    6
dtype: int64

传入axis=1,在列的方向上进行连接,会变成一个DataFrame:

pd.concat([s1,s2,s3], axis=1)
0 1 2
a 0.0 NaN NaN
b 1.0 NaN NaN
c NaN 2.0 NaN
d NaN 3.0 NaN
e NaN 4.0 NaN
f NaN NaN 5.0
g NaN NaN 6.0

concat之后不知道堆叠的数据代表什么,可以通过keys参数设定连接的片段在结果中的索引:

#沿着axis=0对Series进行合并,生成层次化索引
pd.concat([s1,s2,s3], keys = ['s1','s2','s3'])
s1  a    0b    1
s2  c    2d    3e    4
s3  f    5g    6
dtype: int64
#如果沿着axis=1对Series进行合并,则keys就会成为DataFrame的列头:
pd.concat([s1,s2,s3], axis=1, keys = ['s1','s2','s3'])
s1 s2 s3
a 0.0 NaN NaN
b 1.0 NaN NaN
c NaN 2.0 NaN
d NaN 3.0 NaN
e NaN 4.0 NaN
f NaN NaN 5.0
g NaN NaN 6.0

如果索引存在重叠,可以通过join=参数控制连接方式为innerouter(默认为’outer’):

s4 = pd.concat([s1, s3])
s1
a    0
b    1
dtype: int64
s4
a    0
b    1
f    5
g    6
dtype: int64
pd.concat([s1,s4], axis =1)
0 1
a 0.0 0
b 1.0 1
f NaN 5
g NaN 6
pd.concat([s1,s4], axis =1, join='inner')
0 1
a 0 0
b 1 1

上述Series同样的逻辑也适用于DataFrame对象。需说明的是,如果DataFrame的行索引不包含任何有意义的数据,可以通过传入ignore_index=True声明不保留连接轴上的索引,产生一组新索引range(total_length):

df1 = pd.DataFrame(np.random.randn(3, 4), columns=['a', 'b', 'c', 'd'])
df2 = pd.DataFrame(np.random.randn(2, 3), columns=['b', 'd', 'a'])
df1
a b c d
0 0.095987 -1.429683 0.213154 0.209158
1 0.405074 2.060263 0.154940 -1.547939
2 -0.283798 0.185476 -0.833157 0.204095
df2
b d a
0 -0.743573 -0.081083 -0.832971
1 0.432616 -0.393941 -1.465352
pd.concat([df1,df2], ignore_index = True)
a b c d
0 0.095987 -1.429683 0.213154 0.209158
1 0.405074 2.060263 0.154940 -1.547939
2 -0.283798 0.185476 -0.833157 0.204095
3 -0.832971 -0.743573 NaN -0.081083
4 -1.465352 0.432616 NaN -0.393941

合并重叠数据

比如说,你可能有索引全部或部分重叠的两个数据集。你希望用一个数据集去填补另一个数据集中相应字段的缺失值:

s1 = pd.Series([np.nan, 2.5, np.nan, 3.5, 4.5, np.nan],index=['f', 'e', 'd', 'c', 'b', 'a'])
s2 = pd.Series(np.arange(len(a), dtype=np.float64),index=['f', 'e', 'd', 'c', 'b', 'a'])
s2[-1] = np.nan
s1
f    NaN
e    2.5
d    NaN
c    3.5
b    4.5
a    NaN
dtype: float64
s2
f    0.0
e    1.0
d    2.0
c    3.0
b    4.0
a    NaN
dtype: float64

方法一:np.where,表示一种等价于面向数组的if-else

# 条件表达式成立即s1为空值的地方,取s2中值,否则保留s1中值
np.where(pd.isnull(s1), s2, s1)
array([0. , 2.5, 2. , 3.5, 4.5, nan])

方法二:fillna

s1.fillna(s2)
f    0.0
e    2.5
d    2.0
c    3.5
b    4.5
a    NaN
dtype: float64

方法三:combine_first

s1.combine_first(s2)
f    0.0
e    2.5
d    2.0
c    3.5
b    4.5
a    NaN
dtype: float64

以上方法对DataFrame同样适用,用传递对象中的数据为调用对象的缺失数据“打补丁”:

df1 = pd.DataFrame({'a': [1., np.nan, 5., np.nan],'b': [np.nan, 2., np.nan, 6.],'c': range(2, 18, 4)})
df2 = pd.DataFrame({'a': [5., 4., np.nan, 3., 7.],'b': [np.nan, 3., 4., 6., 8.]})
df1
a b c
0 1.0 NaN 2
1 NaN 2.0 6
2 5.0 NaN 10
3 NaN 6.0 14
df2
a b
0 5.0 NaN
1 4.0 3.0
2 NaN 4.0
3 3.0 6.0
4 7.0 8.0
df1.combine_first(df2)
a b c
0 1.0 NaN 2.0
1 4.0 2.0 6.0
2 5.0 4.0 10.0
3 3.0 6.0 14.0
4 7.0 8.0 NaN

层次化索引

层次化索引(hierarchical indexing)是pandas的一项重要功能,它使你能在一个轴上拥有多个(两个以上)索引级别。

对于一个DataFrame,每条轴都可以有分层索引:

frame = pd.DataFrame(np.arange(12).reshape((4, 3)),index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],columns=[['Ohio', 'Ohio', 'Colorado'],['Green', 'Red', 'Green']])
frame
Ohio Colorado
Green Red Green
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11

各层都可以有名字:

frame.index.names = ['key1','key2']
frame.columns.names = ['state','color']
frame
state Ohio Colorado
color Green Red Green
key1 key2
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11

重排与分级排序

swaplevel接受两个级别编号或名称,并返回一个互换了级别的新对象(但数据不会发生变化):

frame.swaplevel(0,1)
state Ohio Colorado
color Green Red Green
key2 key1
1 a 0 1 2
2 a 3 4 5
1 b 6 7 8
2 b 9 10 11
frame.swaplevel('key1','key2')
state Ohio Colorado
color Green Red Green
key2 key1
1 a 0 1 2
2 a 3 4 5
1 b 6 7 8
2 b 9 10 11

sort_index则根据单个级别中的值对数据进行排序。交换级别时,常会用到该命令。

frame.swaplevel('key1','key2').sort_index(level=0)
state Ohio Colorado
color Green Red Green
key2 key1
1 a 0 1 2
b 6 7 8
2 a 3 4 5
b 9 10 11

使用DataFrame的列进行索引

在一些数据分析的场景中,可能想要将DataFrame的一个或多个列当做行索引来用,或者可能希望将行索引变成DataFrame的列。

frame = pd.DataFrame({'a': range(7), 'b': range(7, 0, -1),'c': ['one', 'one', 'one', 'two', 'two', 'two', 'two'],'d': [0, 1, 2, 0, 1, 2, 3]})
frame
a b c d
0 0 7 one 0
1 1 6 one 1
2 2 5 one 2
3 3 4 two 0
4 4 3 two 1
5 5 2 two 2
6 6 1 two 3

DataFrame的set_index函数会将其一个或多个列转换为行索引,并创建一个新的DataFrame:

frame2 = frame.set_index(['c','d'])
frame2
a b
c d
one 0 0 7
1 1 6
2 2 5
two 0 3 4
1 4 3
2 5 2
3 6 1

reset_index的功能跟set_index刚好相反,层次化索引的级别会被转移到列里面:

frame2.reset_index()
c d a b
0 one 0 0 7
1 one 1 1 6
2 one 2 2 5
3 two 0 3 4
4 two 1 4 3
5 two 2 5 2
6 two 3 6 1

数据重塑

层次化索引为DataFrame数据的重排任务提供了一种具有良好一致性的方式。主要功能有二:

  • stack:将数据的列“旋转”为行。
  • unstack:将数据的行“旋转”为列。

比如,以下数据为a、b、c、d四名学生,1、2、3三门课程的考试成绩:

data = pd.DataFrame(list(zip(['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'],[1, 2, 3, 1, 3, 1, 2, 2, 3],np.random.randn(9))),columns = ['student','course','score'])
data
student course score
0 a 1 0.469069
1 a 2 0.568829
2 a 3 1.293216
3 b 1 -0.799458
4 b 3 2.323059
5 c 1 0.419970
6 c 2 0.576399
7 d 2 0.459112
8 d 3 -0.654535

层次化索引在数据重塑和基于分组的操作(如透视表生成)中扮演着重要的角色,例如:

首先,将"student"、"course"设置为index, 形成层次化索引:

data = data.set_index(['student','course'])
data
score
student course
a 1 0.469069
2 0.568829
3 1.293216
b 1 -0.799458
3 2.323059
c 1 0.419970
2 0.576399
d 2 0.459112
3 -0.654535

其次,通过unstack命令对数据进行重塑,得到学生和课程的透视表,这样便于后续对成绩之间进行一些统计运算:

result = data.unstack()
result
score
course 1 2 3
student
a 0.469069 0.568829 1.293216
b -0.799458 NaN 2.323059
c 0.419970 0.576399 NaN
d NaN 0.459112 -0.654535

stack为unstack的逆运算:

result.stack()
score
student course
a 1 0.469069
2 0.568829
3 1.293216
b 1 -0.799458
3 2.323059
c 1 0.419970
2 0.576399
d 2 0.459112
3 -0.654535

往期:
利用Python进行数据分析:准备工作
利用Python进行数据分析:缺失数据(基于DataFrame)
利用Python进行数据分析:数据转换(基于DataFrame)

利用Python进行数据分析:数据规整(基于DataFrame)相关推荐

  1. 利用Python进行数据分析--数据规整化:清理、转换、合并、重塑

    转载自:http://blog.csdn.net/ssw_1990/article/details/26565069 1.数据转换 目前为止介绍的都是数据的重排.另一类重要操作则是过滤.清理以及其他的 ...

  2. 利用Python进行数据分析--数据聚合与分组运算

    转载自:http://blog.csdn.net/ssw_1990/article/details/22422971 1.quantile计算Series或DataFrame列的样本分位数: [pyt ...

  3. 利用Python进行数据分析--数据加载、存储与文件格式

    转载自:http://blog.csdn.net/ssw_1990/article/details/23911901 1.手工处理分隔符格式 大部分存储在磁盘上的表格型数据都能用pandas.read ...

  4. 利用python进行数据分析数据_利用Python进行数据分析

    1.注释以及在Subplot上绘图 除标准的图表对象之外,你可能还希望绘制一些自定义的注释(比如文本.箭头或其他图形等). 注释可以通过text.arrow和annotate等函数进行添加.text可 ...

  5. 利用Python进行数据分析--数据聚合与分组运算1

    转载自:http://blog.csdn.net/ssw_1990/article/details/22286583 pandas提供了一个灵活高效的groupby功能,它使你能以一种自然的方式对数据 ...

  6. 利用python进行数据分析-数据聚合与分组运算2

    1.分组级运算和转换 聚合只不过是分组运算的其中一种而已.介绍transform和apply方法,它们能够执行更多其他的分组运算 假设我们想要为一个DataFrame添加一个用于存放各索引分组平均值的 ...

  7. 利用Python进行数据分析——数据载入、存储及文件格式(7)

    3.数据载入.存储及文件格式   输入和输出通常有以下几种类型:读取文本文件及硬盘上其他更高效的格式文件.从数据库载入数据.与网络资源进行交互(比如Web API). 3.1 文本格式数据的读写    ...

  8. 利用Python进行数据分析——数据导入导出

    一.数据导入 (一)读取CSV文件 1.读取本地CSV #先创建一个CSV文件,存入数据,数据之间以"逗号"分割.  数据源来源于网络. import pandas as pd d ...

  9. 利用Python进行数据分析(7) pandas基础: Series和DataFrame的简单介绍 一、pandas 是什么 pandas 是基于 NumPy 的一个 Python 数据分析包,主

    利用Python进行数据分析(7) pandas基础: Series和DataFrame的简单介绍 一.pandas 是什么 pandas 是基于 NumPy 的一个 Python 数据分析包,主要目 ...

最新文章

  1. 网络服务-RSYNC
  2. Linux 时钟精度 与 PostgreSQL auto_explain (explain timing 时钟开销估算)
  3. python为什么找不到csv文件_python读写csv文件的方法(还没试,先记录一下)
  4. weifenluo与notifyIcon小细节
  5. unity 让一个数按一秒累加_万物皆数—深挖UWA Benchmark之渲染篇
  6. 基于机器学习方法的POI品类推荐算法
  7. Java泛型(1)--集合使用泛型Generic、自定义泛型、泛型在继承上的体现、通配符的使用
  8. android系统app打开蓝牙+设置可见性
  9. hdu-1695 GCD(莫比乌斯反演)
  10. Oracle 11g 服务名称以及作用
  11. 产品管理:四步法新产品开发流程
  12. Python(初学者):调用函数输出
  13. LimeSDR实验教程(5) WiFi解调
  14. 获取 pdf 中某个 关键字的位置
  15. 路由器连接路由器设置教程
  16. (第2课)【初识python爬虫】
  17. oracle修改分区表的默认空间,Oracle数据库学习_Oracle分区表的分区占用空间为什么是8M?如何修改分区的初始空间?...
  18. 宋宝华:为什么numactl内存绑定对代码段不起作用
  19. 16 服务器无响应什么意思,dns电脑服务器未响应是什么意思如何处理
  20. 数组和链表数据结构描述,各自的时间复杂度

热门文章

  1. Cisco 防火墙 技术介绍
  2. 【C语言打印“倒三角形”】
  3. LeetCode 603.连续空余座位
  4. 惠普服务器系统管理 密码,惠普服务器 DL380 Gen9 server2012R2 登录密码找回全过程...
  5. AAAI2020/风格迁移:Ultrafast Photorealistic Style Transfer via Neural Architecture基于神经结构搜索的超快逼真风格转移
  6. YoutubeDL接口参数翻译
  7. 渡一教育公开课web前端开发JavaScript精英课学习笔记(三)条件语句,循环语句
  8. Simplicity and Compromise
  9. 如何查询自家的网络有没有被DNS劫持?dns劫持是什么
  10. 区分与检测null,undefined 与 undeclared