利用Python进行数据分析:数据规整(基于DataFrame)
利用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_index
和left_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=
参数控制连接方式为inner
或outer
(默认为’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)相关推荐
- 利用Python进行数据分析--数据规整化:清理、转换、合并、重塑
转载自:http://blog.csdn.net/ssw_1990/article/details/26565069 1.数据转换 目前为止介绍的都是数据的重排.另一类重要操作则是过滤.清理以及其他的 ...
- 利用Python进行数据分析--数据聚合与分组运算
转载自:http://blog.csdn.net/ssw_1990/article/details/22422971 1.quantile计算Series或DataFrame列的样本分位数: [pyt ...
- 利用Python进行数据分析--数据加载、存储与文件格式
转载自:http://blog.csdn.net/ssw_1990/article/details/23911901 1.手工处理分隔符格式 大部分存储在磁盘上的表格型数据都能用pandas.read ...
- 利用python进行数据分析数据_利用Python进行数据分析
1.注释以及在Subplot上绘图 除标准的图表对象之外,你可能还希望绘制一些自定义的注释(比如文本.箭头或其他图形等). 注释可以通过text.arrow和annotate等函数进行添加.text可 ...
- 利用Python进行数据分析--数据聚合与分组运算1
转载自:http://blog.csdn.net/ssw_1990/article/details/22286583 pandas提供了一个灵活高效的groupby功能,它使你能以一种自然的方式对数据 ...
- 利用python进行数据分析-数据聚合与分组运算2
1.分组级运算和转换 聚合只不过是分组运算的其中一种而已.介绍transform和apply方法,它们能够执行更多其他的分组运算 假设我们想要为一个DataFrame添加一个用于存放各索引分组平均值的 ...
- 利用Python进行数据分析——数据载入、存储及文件格式(7)
3.数据载入.存储及文件格式 输入和输出通常有以下几种类型:读取文本文件及硬盘上其他更高效的格式文件.从数据库载入数据.与网络资源进行交互(比如Web API). 3.1 文本格式数据的读写 ...
- 利用Python进行数据分析——数据导入导出
一.数据导入 (一)读取CSV文件 1.读取本地CSV #先创建一个CSV文件,存入数据,数据之间以"逗号"分割. 数据源来源于网络. import pandas as pd d ...
- 利用Python进行数据分析(7) pandas基础: Series和DataFrame的简单介绍 一、pandas 是什么 pandas 是基于 NumPy 的一个 Python 数据分析包,主
利用Python进行数据分析(7) pandas基础: Series和DataFrame的简单介绍 一.pandas 是什么 pandas 是基于 NumPy 的一个 Python 数据分析包,主要目 ...
最新文章
- 网络服务-RSYNC
- Linux 时钟精度 与 PostgreSQL auto_explain (explain timing 时钟开销估算)
- python为什么找不到csv文件_python读写csv文件的方法(还没试,先记录一下)
- weifenluo与notifyIcon小细节
- unity 让一个数按一秒累加_万物皆数—深挖UWA Benchmark之渲染篇
- 基于机器学习方法的POI品类推荐算法
- Java泛型(1)--集合使用泛型Generic、自定义泛型、泛型在继承上的体现、通配符的使用
- android系统app打开蓝牙+设置可见性
- hdu-1695 GCD(莫比乌斯反演)
- Oracle 11g 服务名称以及作用
- 产品管理:四步法新产品开发流程
- Python(初学者):调用函数输出
- LimeSDR实验教程(5) WiFi解调
- 获取 pdf 中某个 关键字的位置
- 路由器连接路由器设置教程
- (第2课)【初识python爬虫】
- oracle修改分区表的默认空间,Oracle数据库学习_Oracle分区表的分区占用空间为什么是8M?如何修改分区的初始空间?...
- 宋宝华:为什么numactl内存绑定对代码段不起作用
- 16 服务器无响应什么意思,dns电脑服务器未响应是什么意思如何处理
- 数组和链表数据结构描述,各自的时间复杂度
热门文章
- Cisco 防火墙 技术介绍
- 【C语言打印“倒三角形”】
- LeetCode 603.连续空余座位
- 惠普服务器系统管理 密码,惠普服务器 DL380 Gen9 server2012R2 登录密码找回全过程...
- AAAI2020/风格迁移:Ultrafast Photorealistic Style Transfer via Neural Architecture基于神经结构搜索的超快逼真风格转移
- YoutubeDL接口参数翻译
- 渡一教育公开课web前端开发JavaScript精英课学习笔记(三)条件语句,循环语句
- Simplicity and Compromise
- 如何查询自家的网络有没有被DNS劫持?dns劫持是什么
- 区分与检测null,undefined 与 undeclared