7.1 Pandas
原文:Pandas 译者:飞龙 协议:CC BY-NC-SA 4.0 致谢:这个笔记摘自 Wes McKinney 的著作 《Python 数据分析》(Python for Data Analysis)
- 序列(
Series
) - 数据帧(
DataFrame
) - 重索引
- 删除条目
- 索引,选择和过滤
- 算术和数据对齐
- 函数应用和映射
- 排序和排名
- 带有重复值的轴索引
- 汇总和计算描述性统计量
- 清洗数据(构建中)
- 输入和输出(构建中)
from pandas import Series, DataFrame
import pandas as pd
import numpy as np
序列(Series
)
Series
是一维数组对象,包含数据数组和相关的数据标签数组。数据可以是任何 NumPy 数据类型,标签是序列的索引。
创建Series
:
ser_1 = Series([1, 1, 2, -3, -5, 8, 13])
ser_1
'''
0 1
1 1
2 2
3 -3
4 -5
5 8
6 13
dtype: int64
'''
获取Series
的数组表示:
ser_1.values
# array([ 1, 1, 2, -3, -5, 8, 13])
Series
对象是不可变的,并持有轴标签和元数据,如名称和轴名称。
获取Series
的索引:
ser_1.index
# Int64Index([0, 1, 2, 3, 4, 5, 6], dtype='int64')
使用自定义索引创建Series
:
ser_2 = Series([1, 1, 2, -3, -5], index=['a', 'b', 'c', 'd', 'e'])
ser_2
'''
a 1
b 1
c 2
d -3
e -5
dtype: int64
'''
从Series
获取值:
ser_2[4] == ser_2['e']
# True
通过传入列表从Series
获取一组值:
ser_2[['c', 'a', 'b']]
'''
c 2
a 1
b 1
dtype: int64
'''
获取大于 0 的值:
代码语言:javascript复制ser_2[ser_2 > 0]
'''
a 1
b 1
c 2
dtype: int64
'''
标量乘法:
代码语言:javascript复制ser_2 * 2
'''
a 2
b 2
c 4
d -6
e -10
dtype: int64
'''
应用 NumPy 数学函数:
代码语言:javascript复制import numpy as np
np.exp(ser_2)
'''
a 2.718282
b 2.718282
c 7.389056
d 0.049787
e 0.006738
dtype: float64
'''
Series
就像一个固定长度的有序字典。
传入字典来创建Series
:
dict_1 = {'foo' : 100, 'bar' : 200, 'baz' : 300}
ser_3 = Series(dict_1)
ser_3
'''
bar 200
baz 300
foo 100
dtype: int64
'''
通过传入索引来重排Series
(未找到的索引是 NaN):
index = ['foo', 'bar', 'baz', 'qux']
ser_4 = Series(dict_1, index=index)
ser_4
'''
foo 100
bar 200
baz 300
qux NaN
dtype: float64
'''
使用 pandas 方法检查 NaN:
代码语言:javascript复制pd.isnull(ser_4)
'''
foo False
bar False
baz False
qux True
dtype: bool
'''
使用Series
的方法检查 NaN:
ser_4.isnull()
'''
foo False
bar False
baz False
qux True
dtype: bool
'''
在算术运算中,Series
自动对齐不同的索引数据:
ser_3 ser_4
'''
bar 400
baz 600
foo 200
qux NaN
dtype: float64
'''
命名Series
:
ser_4.name = 'foobarbazqux'
命名Series
索引:
ser_4.index.name = 'label'
ser_4
'''
label
foo 100
bar 200
baz 300
qux NaN
Name: foobarbazqux, dtype: float64
'''
原地重命名Series
的索引:
ser_4.index = ['fo', 'br', 'bz', 'qx']
ser_4
'''
fo 100
br 200
bz 300
qx NaN
Name: foobarbazqux, dtype: float64
'''
数据帧(DataFrame
)
DataFrame
是表格数据结构,包含列的有序集合。 每列可以是不同的类型。 DataFrame
同时具有行索引和列索引,类似于Series
的字典。行和列操作大致是对称实现的。 索引DataFrame
时返回的列是底层数据的视图,而不是副本。 要获取副本,请使用Series
的复制方法。
创建DataFrame
:
data_1 = {'state' : ['VA', 'VA', 'VA', 'MD', 'MD'],
'year' : [2012, 2013, 2014, 2014, 2015],
'pop' : [5.0, 5.1, 5.2, 4.0, 4.1]}
df_1 = DataFrame(data_1)
df_1
pop | state | year | |
---|---|---|---|
0 | 5.0 | VA | 2012 |
1 | 5.1 | VA | 2013 |
2 | 5.2 | VA | 2014 |
3 | 4.0 | MD | 2014 |
4 | 4.1 | MD | 2015 |
指定列的序列来创建DataFrame
:
df_2 = DataFrame(data_1, columns=['year', 'state', 'pop'])
df_2
| | year | state | pop | | — | — | — | | 0 | 2012 | VA | 5.0 | | 1 | 2013 | VA | 5.1 | | 2 | 2014 | VA | 5.2 | | 3 | 2014 | MD | 4.0 | | 4 | 2015 | MD | 4.1 |
与Series
类似,数据中不存在的列是 NaN:
df_3 = DataFrame(data_1, columns=['year', 'state', 'pop', 'unempl'])
df_3
year | state | pop | unempl | |
---|---|---|---|---|
0 | 2012 | VA | 5.0 | NaN |
1 | 2013 | VA | 5.1 | NaN |
2 | 2014 | VA | 5.2 | NaN |
3 | 2014 | MD | 4.0 | NaN |
4 | 2015 | MD | 4.1 | NaN |
通过键检索列,返回Series
:
df_3['state']
'''
0 VA
1 VA
2 VA
3 MD
4 MD
Name: state, dtype: object
'''
通过属性检索列,返回Series
:
df_3.year
'''
0 2012
1 2013
2 2014
3 2014
4 2015
Name: year, dtype: int64
'''
通过位置检索行:
代码语言:javascript复制df_3.ix[0]
'''
year 2012
state VA
pop 5
unempl NaN
Name: 0, dtype: object
'''
通过复制来更新列:
代码语言:javascript复制df_3['unempl'] = np.arange(5)
df_3
| | year | state | pop | unempl | | — | — | — | — | | 0 | 2012 | VA | 5.0 | 0 | | 1 | 2013 | VA | 5.1 | 1 | | 2 | 2014 | VA | 5.2 | 2 | | 3 | 2014 | MD | 4.0 | 3 | | 4 | 2015 | MD | 4.1 | 4 |
将Series
赋给列(请注意,如果指定了列表或数组,则长度必须与DataFrame
匹配,与Series
不同):
unempl = Series([6.0, 6.0, 6.1], index=[2, 3, 4])
df_3['unempl'] = unempl
df_3
year | state | pop | unempl | |
---|---|---|---|---|
0 | 2012 | VA | 5.0 | NaN |
1 | 2013 | VA | 5.1 | NaN |
2 | 2014 | VA | 5.2 | 6.0 |
3 | 2014 | MD | 4.0 | 6.0 |
4 | 2015 | MD | 4.1 | 6.1 |
对不存在的新列赋值来创建新列:
代码语言:javascript复制df_3['state_dup'] = df_3['state']
df_3
year | state | pop | unempl | state_dup | |
---|---|---|---|---|---|
0 | 2012 | VA | 5.0 | NaN | VA |
1 | 2013 | VA | 5.1 | NaN | VA |
2 | 2014 | VA | 5.2 | 6.0 | VA |
3 | 2014 | MD | 4.0 | 6.0 | MD |
4 | 2015 | MD | 4.1 | 6.1 | MD |
删除一列:
代码语言:javascript复制del df_3['state_dup']
df_3
year | state | pop | unempl | |
---|---|---|---|---|
0 | 2012 | VA | 5.0 | NaN |
1 | 2013 | VA | 5.1 | NaN |
2 | 2014 | VA | 5.2 | 6.0 |
3 | 2014 | MD | 4.0 | 6.0 |
4 | 2015 | MD | 4.1 | 6.1 |
从字典的嵌套字典创建DataFrame
(如果没有指定显示索引,内部字典中的键,被合并并排序来形成结果中的索引):
pop = {'VA' : {2013 : 5.1, 2014 : 5.2},
'MD' : {2014 : 4.0, 2015 : 4.1}}
df_4 = DataFrame(pop)
df_4
MD | VA | |
---|---|---|
2013 | NaN | 5.1 |
2014 | 4.0 | 5.2 |
2015 | 4.1 | NaN |
转置DataFrame
:
df_4.T
2013 | 2014 | 2015 | |
---|---|---|---|
MD | NaN | 4.0 | 4.1 |
VA | 5.1 | 5.2 | NaN |
从Series
的词典创建一个DataFrame
:
data_2 = {'VA' : df_4['VA'][1:],
'MD' : df_4['MD'][2:]}
df_5 = DataFrame(data_2)
df_5
MD | VA | |
---|---|---|
2014 | NaN | 5.2 |
2015 | 4.1 | NaN |
设置DataFrame
的索引名称:
df_5.index.name = 'year'
df_5
MD | VA | |
---|---|---|
year | ||
2014 | NaN | 5.2 |
2015 | 4.1 | NaN |
设置DataFrame
的列名称:
df_5.columns.name = 'state'
df_5
state | MD | VA |
---|---|---|
year | ||
2014 | NaN | 5.2 |
2015 | 4.1 | NaN |
将DataFrame
中包含的数据作为 2D ndarray
返回:
df_5.values
'''
array([[ nan, 5.2],
[ 4.1, nan]])
'''
如果列是不同的dtypes
,则 2D 数组的dtype
将兼容所有列:
df_3.values
'''
array([[2012, 'VA', 5.0, nan],
[2013, 'VA', 5.1, nan],
[2014, 'VA', 5.2, 6.0],
[2014, 'MD', 4.0, 6.0],
[2015, 'MD', 4.1, 6.1]], dtype=object)
'''
重索引
使用符合新索引的数据创建新对象。任何缺失值都设置为 NaN。
代码语言:javascript复制df_3
year | state | pop | unempl | |
---|---|---|---|---|
0 | 2012 | VA | 5.0 | NaN |
1 | 2013 | VA | 5.1 | NaN |
2 | 2014 | VA | 5.2 | 6.0 |
3 | 2014 | MD | 4.0 | 6.0 |
4 | 2015 | MD | 4.1 | 6.1 |
行的重新索引将返回具有指定索引的新DataFrame
:
df_3.reindex(list(reversed(range(0, 6))))
year | state | pop | unempl | |
---|---|---|---|---|
5 | NaN | NaN | NaN | NaN |
4 | 2015 | MD | 4.1 | 6.1 |
3 | 2014 | MD | 4.0 | 6.0 |
2 | 2014 | VA | 5.2 | 6.0 |
1 | 2013 | VA | 5.1 | NaN |
0 | 2012 | VA | 5.0 | NaN |
缺失值可以设置为 NaN 以外的值:
代码语言:javascript复制df_3.reindex(range(6, 0), fill_value=0)
year | state | pop | unempl |
---|
插入有序数据,如时间序列:
代码语言:javascript复制ser_5 = Series(['foo', 'bar', 'baz'], index=[0, 2, 4])
ser_5.reindex(range(5), method='ffill')
'''
0 foo
1 foo
2 bar
3 bar
4 baz
dtype: object
'''
ser_5.reindex(range(5), method='bfill')
'''
0 foo
1 bar
2 bar
3 baz
4 baz
dtype: object
'''
重索引列:
代码语言:javascript复制df_3.reindex(columns=['state', 'pop', 'unempl', 'year'])
state | pop | unempl | year | |
---|---|---|---|---|
0 | VA | 5.0 | NaN | 2012 |
1 | VA | 5.1 | NaN | 2013 |
2 | VA | 5.2 | 6.0 | 2014 |
3 | MD | 4.0 | 6.0 | 2014 |
4 | MD | 4.1 | 6.1 | 2015 |
重新索引行和列,同时填充行:
代码语言:javascript复制df_3.reindex(index=list(reversed(range(0, 6))),
fill_value=0,
columns=['state', 'pop', 'unempl', 'year'])
state | pop | unempl | year | |
---|---|---|---|---|
5 | 0 | 0.0 | 0.0 | 0 |
4 | MD | 4.1 | 6.1 | 2015 |
3 | MD | 4.0 | 6.0 | 2014 |
2 | VA | 5.2 | 6.0 | 2014 |
1 | VA | 5.1 | NaN | 2013 |
0 | VA | 5.0 | NaN | 2012 |
使用ix
的重索引:
df_6 = df_3.ix[range(0, 7), ['state', 'pop', 'unempl', 'year']]
df_6
state | pop | unempl | year | |
---|---|---|---|---|
0 | VA | 5.0 | NaN | 2012 |
1 | VA | 5.1 | NaN | 2013 |
2 | VA | 5.2 | 6.0 | 2014 |
3 | MD | 4.0 | 6.0 | 2014 |
4 | MD | 4.1 | 6.1 | 2015 |
5 | NaN | NaN | NaN | NaN |
6 | NaN | NaN | NaN | NaN |
删除条目
从Series
或DataFrame
中删除行:
df_7 = df_6.drop([0, 1])
df_7
state | pop | unempl | year | |
---|---|---|---|---|
2 | VA | 5.2 | 6.0 | 2014 |
3 | MD | 4.0 | 6.0 | 2014 |
4 | MD | 4.1 | 6.1 | 2015 |
5 | NaN | NaN | NaN | NaN |
6 | NaN | NaN | NaN | NaN |
从DataFrame
中删除列:
df_7 = df_7.drop('unempl', axis=1)
df_7
state | pop | year | |
---|---|---|---|
2 | VA | 5.2 | 2014 |
3 | MD | 4.0 | 2014 |
4 | MD | 4.1 | 2015 |
5 | NaN | NaN | NaN |
6 | NaN | NaN | NaN |
索引,选择和过滤
Series
索引类似于 NumPy 数组索引,并且能够使用Series
的索引值。
ser_2
'''
a 1
b 1
c 2
d -3
e -5
dtype: int64
'''
从Series
中选择值:
ser_2[0] == ser_2['a']
# True
从Series
中选择切片:
ser_2[1:4]
'''
b 1
c 2
d -3
dtype: int64
'''
从Series
中选择特定值:
ser_2[['b', 'c', 'd']]
'''
b 1
c 2
d -3
dtype: int64
'''
基于过滤器从Series
中选择值:
ser_2[ser_2 > 0]
'''
a 1
b 1
c 2
dtype: int64
'''
从带标签的Series
中选择切片(注意包含终点):
ser_2['a':'b']
'''
a 1
b 1
dtype: int64
'''
对Series
切片赋值(注意包含终点):
ser_2['a':'b'] = 0
ser_2
'''
a 0
b 0
c 2
d -3
e -5
dtype: int64
'''
Pandas 支持DataFrame
中的索引。
df_6
state | pop | unempl | year | |
---|---|---|---|---|
0 | VA | 5.0 | NaN | 2012 |
1 | VA | 5.1 | NaN | 2013 |
2 | VA | 5.2 | 6.0 | 2014 |
3 | MD | 4.0 | 6.0 | 2014 |
4 | MD | 4.1 | 6.1 | 2015 |
5 | NaN | NaN | NaN | NaN |
6 | NaN | NaN | NaN | NaN |
从DataFrame
中选择特定列:
df_6[['pop', 'unempl']]
pop | unempl | |
---|---|---|
0 | 5.0 | NaN |
1 | 5.1 | NaN |
2 | 5.2 | 6.0 |
3 | 4.0 | 6.0 |
4 | 4.1 | 6.1 |
5 | NaN | NaN |
6 | NaN | NaN |
从DataFrame
中选择切片:
df_6[:2]
state | pop | unempl | year | |
---|---|---|---|---|
0 | VA | 5.0 | NaN | 2012 |
1 | VA | 5.1 | NaN | 2013 |
基于过滤器从DataFrame
中选择行:
df_6[df_6['pop'] > 5]
state | pop | unempl | year | |
---|---|---|---|---|
1 | VA | 5.1 | NaN | 2013 |
2 | VA | 5.2 | 6 | 2014 |
在DataFrame
上执行标量比较:
df_6 > 5
state | pop | unempl | year | |
---|---|---|---|---|
0 | True | False | False | True |
1 | True | True | False | True |
2 | True | True | True | True |
3 | True | False | True | True |
4 | True | False | True | True |
5 | True | False | False | False |
6 | True | False | False | False |
在DataFrame
上执行标量比较,保留满足过滤器的行:
df_6[df_6 > 5]
state | pop | unempl | year | |
---|---|---|---|---|
0 | VA | NaN | NaN | 2012 |
1 | VA | 5.1 | NaN | 2013 |
2 | VA | 5.2 | 6.0 | 2014 |
3 | MD | NaN | 6.0 | 2014 |
4 | MD | NaN | 6.1 | 2015 |
5 | NaN | NaN | NaN | NaN |
6 | NaN | NaN | NaN | NaN |
从DataFrame
中选择一行(注意包含终点):
df_6.ix[2:3]
state | pop | unempl | year | |
---|---|---|---|---|
2 | VA | 5.2 | 6 | 2014 |
3 | MD | 4.0 | 6 | 2014 |
从DataFrame
的特定列中选择行的切片:
df_6.ix[0:2, 'pop']
'''
0 5.0
1 5.1
2 5.2
Name: pop, dtype: float64
'''
根据特定行上的算术运算选择行:
代码语言:javascript复制df_6.ix[df_6.unempl > 5.0]
state | pop | unempl | year | |
---|---|---|---|---|
2 | VA | 5.2 | 6.0 | 2014 |
3 | MD | 4.0 | 6.0 | 2014 |
4 | MD | 4.1 | 6.1 | 2015 |
算术和数据对齐
如果索引对不相同,则将Series
对象相加会产生索引对的并集,使不重叠的索引为 NaN:
np.random.seed(0)
ser_6 = Series(np.random.randn(5),
index=['a', 'b', 'c', 'd', 'e'])
ser_6
'''
a 1.764052
b 0.400157
c 0.978738
d 2.240893
e 1.867558
dtype: float64
'''
np.random.seed(1)
ser_7 = Series(np.random.randn(5),
index=['a', 'c', 'e', 'f', 'g'])
ser_7
'''
a 1.624345
c -0.611756
e -0.528172
f -1.072969
g 0.865408
dtype: float64
'''
ser_6 ser_7
'''
a 3.388398
b NaN
c 0.366982
d NaN
e 1.339386
f NaN
g NaN
dtype: float64
'''
为不重叠的索引设置填充值而不是 NaN:
代码语言:javascript复制ser_6.add(ser_7, fill_value=0)
'''
a 3.388398
b 0.400157
c 0.366982
d 2.240893
e 1.339386
f -1.072969
g 0.865408
dtype: float64
'''
如果索引对不相同,则将DataFrame
对象相加,会产生行和列的索引对的并集,使不重叠的索引为 NaN:
np.random.seed(0)
df_8 = DataFrame(np.random.rand(9).reshape((3, 3)),
columns=['a', 'b', 'c'])
df_8
a | b | c | |
---|---|---|---|
0 | 0.548814 | 0.715189 | 0.602763 |
1 | 0.544883 | 0.423655 | 0.645894 |
2 | 0.437587 | 0.891773 | 0.963663 |
np.random.seed(1)
df_9 = DataFrame(np.random.rand(9).reshape((3, 3)),
columns=['b', 'c', 'd'])
df_9
b | c | d | |
---|---|---|---|
0 | 0.417022 | 0.720324 | 0.000114 |
1 | 0.302333 | 0.146756 | 0.092339 |
2 | 0.186260 | 0.345561 | 0.396767 |
df_8 df_9
a | b | c | d | |
---|---|---|---|---|
0 | NaN | 1.132211 | 1.323088 | NaN |
1 | NaN | 0.725987 | 0.792650 | NaN |
2 | NaN | 1.078033 | 1.309223 | NaN |
为不重叠的索引设置填充值而不是 NaN:
代码语言:javascript复制df_10 = df_8.add(df_9, fill_value=0)
df_10
a | b | c | d | |
---|---|---|---|---|
0 | 0.548814 | 1.132211 | 1.323088 | 0.000114 |
1 | 0.544883 | 0.725987 | 0.792650 | 0.092339 |
2 | 0.437587 | 1.078033 | 1.309223 | 0.396767 |
与 NumPy 一样,pandas 支持DataFrame
和Series
之间的算术运算。
在DataFrame
的列上匹配Series
的索引,并向下广播行:
ser_8 = df_10.ix[0]
df_11 = df_10 - ser_8
df_11
a | b | c | d | |
---|---|---|---|---|
0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
1 | -0.003930 | -0.406224 | -0.530438 | 0.092224 |
2 | -0.111226 | -0.054178 | -0.013864 | 0.396653 |
在DataFrame
的列上匹配Series
的索引,向下广播行并合并不匹配的索引:
ser_9 = Series(range(3), index=['a', 'd', 'e'])
ser_9
'''
a 0
d 1
e 2
dtype: int64
'''
df_11 - ser_9
a | b | c | d | e | |
---|---|---|---|---|---|
0 | 0.000000 | NaN | NaN | -1.000000 | NaN |
1 | -0.003930 | NaN | NaN | -0.907776 | NaN |
2 | -0.111226 | NaN | NaN | -0.603347 | NaN |
使用算术方法,在列上广播并匹配行(axis = 0
):
df_10
a | b | c | d | |
---|---|---|---|---|
0 | 0.548814 | 1.132211 | 1.323088 | 0.000114 |
1 | 0.544883 | 0.725987 | 0.792650 | 0.092339 |
2 | 0.437587 | 1.078033 | 1.309223 | 0.396767 |
ser_10 = Series([100, 200, 300])
ser_10
'''
0 100
1 200
2 300
dtype: int64
'''
df_10.sub(ser_10, axis=0)
a | b | c | d | |
---|---|---|---|---|
0 | -99.451186 | -98.867789 | -98.676912 | -99.999886 |
1 | -199.455117 | -199.274013 | -199.207350 | -199.907661 |
2 | -299.562413 | -298.921967 | -298.690777 | -299.603233 |
函数应用和映射
NumPy ufunc
(逐元素数组方法)能够操作 pandas 对象:
df_11 = np.abs(df_11)
df_11
a | b | c | d | |
---|---|---|---|---|
0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
1 | 0.003930 | 0.406224 | 0.530438 | 0.092224 |
2 | 0.111226 | 0.054178 | 0.013864 | 0.396653 |
将 1D 数组上的函数应用于每列:
代码语言:javascript复制func_1 = lambda x: x.max() - x.min()
df_11.apply(func_1)
'''
a 0.111226
b 0.406224
c 0.530438
d 0.396653
dtype: float64
'''
将 1D 数组上的函数应用于每行:
代码语言:javascript复制df_11.apply(func_1, axis=1)
'''
0 0.000000
1 0.526508
2 0.382789
dtype: float64
'''
应用函数并返回DataFrame
:
func_2 = lambda x: Series([x.min(), x.max()], index=['min', 'max'])
df_11.apply(func_2)
a | b | c | d | |
---|---|---|---|---|
min | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
max | 0.111226 | 0.406224 | 0.530438 | 0.396653 |
将逐元素的 Python 函数应用于DataFrame
:
func_3 = lambda x: '%.2f' %x
df_11.applymap(func_3)
a | b | c | d | |
---|---|---|---|---|
0 | 0.00 | 0.00 | 0.00 | 0.00 |
1 | 0.00 | 0.41 | 0.53 | 0.09 |
2 | 0.11 | 0.05 | 0.01 | 0.40 |
将逐元素的 Python 函数应用于Series
:
df_11['a'].map(func_3)
'''
0 0.00
1 0.00
2 0.11
Name: a, dtype: object
'''
排序和排名
代码语言:javascript复制ser_4
'''
fo 100
br 200
bz 300
qx NaN
Name: foobarbazqux, dtype: float64
'''
按照索引排序Series
:
ser_4.sort_index()
'''
br 200
bz 300
fo 100
qx NaN
Name: foobarbazqux, dtype: float64
'''
按照值排序Series
:
ser_4.sort_values()
'''
fo 100
br 200
bz 300
qx NaN
Name: foobarbazqux, dtype: float64
'''
df_12 = DataFrame(np.arange(12).reshape((3, 4)),
index=['three', 'one', 'two'],
columns=['c', 'a', 'b', 'd'])
df_12
c | a | b | d | |
---|---|---|---|---|
three | 0 | 1 | 2 | 3 |
one | 4 | 5 | 6 | 7 |
two | 8 | 9 | 10 | 11 |
按照索引排序DaraFrame
:
df_12.sort_index()
c | a | b | d | |
---|---|---|---|---|
one | 4 | 5 | 6 | 7 |
three | 0 | 1 | 2 | 3 |
two | 8 | 9 | 10 | 11 |
按列倒序排序DaraFrame
:
df_12.sort_index(axis=1, ascending=False)
d | c | b | a | |
---|---|---|---|---|
three | 3 | 0 | 2 | 1 |
one | 7 | 4 | 6 | 5 |
two | 11 | 8 | 10 | 9 |
按列排序DaraFrame
的值:
df_12.sort_values(by=['d', 'c'])
c | a | b | d | |
---|---|---|---|---|
three | 0 | 1 | 2 | 3 |
one | 4 | 5 | 6 | 7 |
two | 8 | 9 | 10 | 11 |
排名类似于numpy.argsort
,除了通过为每个组分配平均排名来打破关系:
ser_11 = Series([7, -5, 7, 4, 2, 0, 4, 7])
ser_11 = ser_11.sort_values()
ser_11
'''
1 -5
5 0
4 2
3 4
6 4
0 7
2 7
7 7
dtype: int64
'''
ser_11.rank()
'''
1 1.0
5 2.0
4 3.0
3 4.5
6 4.5
0 7.0
2 7.0
7 7.0
dtype: float64
'''
根据数据出现在Series
中的位置,来排名Series
:
ser_11.rank(method='first')
'''
1 1
5 2
4 3
3 4
6 5
0 6
2 7
7 8
dtype: float64
'''
使用分组的最大排名,降序排列Series
:
ser_11.rank(ascending=False, method='max')
'''
1 8
5 7
4 6
3 5
6 5
0 3
2 3
7 3
dtype: float64
'''
DataFrame
可以按行或列排名。
df_13 = DataFrame({'foo' : [7, -5, 7, 4, 2, 0, 4, 7],
'bar' : [-5, 4, 2, 0, 4, 7, 7, 8],
'baz' : [-1, 2, 3, 0, 5, 9, 9, 5]})
df_13
bar | baz | foo | |
---|---|---|---|
0 | -5 | -1 | 7 |
1 | 4 | 2 | -5 |
2 | 2 | 3 | 7 |
3 | 0 | 0 | 4 |
4 | 4 | 5 | 2 |
5 | 7 | 9 | 0 |
6 | 7 | 9 | 4 |
7 | 8 | 5 | 7 |
在行上(按列)排名DataFrame
:
df_13.rank()
bar | baz | foo | |
---|---|---|---|
0 | 1.0 | 1.0 | 7.0 |
1 | 4.5 | 3.0 | 1.0 |
2 | 3.0 | 4.0 | 7.0 |
3 | 2.0 | 2.0 | 4.5 |
4 | 4.5 | 5.5 | 3.0 |
5 | 6.5 | 7.5 | 2.0 |
6 | 6.5 | 7.5 | 4.5 |
7 | 8.0 | 5.5 | 7.0 |
在列上(按行)排名DataFrame
:
df_13.rank(axis=1)
bar | baz | foo | |
---|---|---|---|
0 | 1.0 | 2.0 | 3 |
1 | 3.0 | 2.0 | 1 |
2 | 1.0 | 2.0 | 3 |
3 | 1.5 | 1.5 | 3 |
4 | 2.0 | 3.0 | 1 |
5 | 2.0 | 3.0 | 1 |
6 | 2.0 | 3.0 | 1 |
7 | 3.0 | 1.0 | 2 |
带有重复值的轴索引
标签在 Pandas 中不一定是唯一的:
代码语言:javascript复制ser_12 = Series(range(5), index=['foo', 'foo', 'bar', 'bar', 'baz'])
ser_12
'''
foo 0
foo 1
bar 2
bar 3
baz 4
dtype: int64
'''
ser_12.index.is_unique
# False
选择序列的元素:
代码语言:javascript复制ser_12['foo']
'''
foo 0
foo 1
dtype: int64
'''
选择DataFrame
的元素:
df_14 = DataFrame(np.random.randn(5, 4),
index=['foo', 'foo', 'bar', 'bar', 'baz'])
df_14
0 | 1 | 2 | 3 | |
---|---|---|---|---|
foo | -2.363469 | 1.135345 | -1.017014 | 0.637362 |
foo | -0.859907 | 1.772608 | -1.110363 | 0.181214 |
bar | 0.564345 | -0.566510 | 0.729976 | 0.372994 |
bar | 0.533811 | -0.091973 | 1.913820 | 0.330797 |
baz | 1.141943 | -1.129595 | -0.850052 | 0.960820 |
df_14.ix['bar']
0 | 1 | 2 | 3 | |
---|---|---|---|---|
bar | 0.564345 | -0.566510 | 0.729976 | 0.372994 |
bar | 0.533811 | -0.091973 | 1.913820 | 0.330797 |
汇总和计算描述性统计量
与 NumPy 数组不同,Pandas 描述性统计量会自动排除缺失数据。 除非整行或列为 NA,否则将排除 NaN 值。
代码语言:javascript复制df_6
state | pop | unempl | year | |
---|---|---|---|---|
0 | VA | 5.0 | NaN | 2012 |
1 | VA | 5.1 | NaN | 2013 |
2 | VA | 5.2 | 6.0 | 2014 |
3 | MD | 4.0 | 6.0 | 2014 |
4 | MD | 4.1 | 6.1 | 2015 |
5 | NaN | NaN | NaN | NaN |
6 | NaN | NaN | NaN | NaN |
df_6.sum()
'''
pop 23.4
unempl 18.1
year 10068.0
dtype: float64
'''
按行求和:
代码语言:javascript复制df_6.sum(axis=1)
'''
0 2017.0
1 2018.1
2 2025.2
3 2024.0
4 2025.2
5 0.0
6 0.0
dtype: float64
'''
计入 NaN:
代码语言:javascript复制df_6.sum(axis=1, skipna=False)
'''
0 NaN
1 NaN
2 2025.2
3 2024.0
4 2025.2
5 NaN
6 NaN
dtype: float64
'''
清洗数据(构建中)
- 替换
- 删除
- 连接
from pandas import Series, DataFrame
import pandas as pd
创建DataFrame
:
data_1 = {'state' : ['VA', 'VA', 'VA', 'MD', 'MD'],
'year' : [2012, 2013, 2014, 2014, 2015],
'population' : [5.0, 5.1, 5.2, 4.0, 4.1]}
df_1 = DataFrame(data_1)
df_1
population | state | year | |
---|---|---|---|
0 | 5.0 | VA | 2012 |
1 | 5.1 | VA | 2013 |
2 | 5.2 | VA | 2014 |
3 | 4.0 | MD | 2014 |
4 | 4.1 | MD | 2015 |
替换
将字符串的所有出现替换为另一个字符串(不复制):
代码语言:javascript复制df_1.replace('VA', 'VIRGINIA', inplace=True)
df_1
population | state | year | |
---|---|---|---|
0 | 5.0 | VIRGINIA | 2012 |
1 | 5.1 | VIRGINIA | 2013 |
2 | 5.2 | VIRGINIA | 2014 |
3 | 4.0 | MD | 2014 |
4 | 4.1 | MD | 2015 |
在指定的列中,将字符串的所有出现替换为另一个字符串(不复制):
代码语言:javascript复制df_1.replace({'state' : { 'MD' : 'MARYLAND' }}, inplace=True)
df_1
population | state | year | |
---|---|---|---|
0 | 5.0 | VIRGINIA | 2012 |
1 | 5.1 | VIRGINIA | 2013 |
2 | 5.2 | VIRGINIA | 2014 |
3 | 4.0 | MARYLAND | 2014 |
4 | 4.1 | MARYLAND | 2015 |
删除
删除'population'
列并返回DataFrame
的副本:
df_2 = df_1.drop('population', axis=1)
df_2
state | year | |
---|---|---|
0 | VIRGINIA | 2012 |
1 | VIRGINIA | 2013 |
2 | VIRGINIA | 2014 |
3 | MARYLAND | 2014 |
4 | MARYLAND | 2015 |
连接
连接两个DaraFrame
:
data_2 = {'state' : ['NY', 'NY', 'NY', 'FL', 'FL'],
'year' : [2012, 2013, 2014, 2014, 2015],
'population' : [6.0, 6.1, 6.2, 3.0, 3.1]}
df_3 = DataFrame(data_2)
df_3
population | state | year | |
---|---|---|---|
0 | 6.0 | NY | 2012 |
1 | 6.1 | NY | 2013 |
2 | 6.2 | NY | 2014 |
3 | 3.0 | FL | 2014 |
4 | 3.1 | FL | 2015 |
df_4 = pd.concat([df_1, df_3])
df_4
population | state | year | |
---|---|---|---|
0 | 5.0 | VIRGINIA | 2012 |
1 | 5.1 | VIRGINIA | 2013 |
2 | 5.2 | VIRGINIA | 2014 |
3 | 4.0 | MARYLAND | 2014 |
4 | 4.1 | MARYLAND | 2015 |
0 | 6.0 | NY | 2012 |
1 | 6.1 | NY | 2013 |
2 | 6.2 | NY | 2014 |
3 | 3.0 | FL | 2014 |
4 | 3.1 | FL | 2015 |
输入和输出(构建中)
- 读
- 写
from pandas import Series, DataFrame
import pandas as pd
读
将 CSV 文件中的数据读入DataFrame
(对 TSV 使用sep='t'
):
df_1 = pd.read_csv("../data/ozone.csv")
获取DataFrame
的摘要:
df_1.describe()
Ozone | Solar.R | Wind | Temp | Month | Day | |
---|---|---|---|---|---|---|
count | 116.000000 | 146.000000 | 153.000000 | 153.000000 | 153.000000 | 153.000000 |
mean | 42.129310 | 185.931507 | 9.957516 | 77.882353 | 6.993464 | 15.803922 |
std | 32.987885 | 90.058422 | 3.523001 | 9.465270 | 1.416522 | 8.864520 |
min | 1.000000 | 7.000000 | 1.700000 | 56.000000 | 5.000000 | 1.000000 |
25% | 18.000000 | 115.750000 | 7.400000 | 72.000000 | 6.000000 | 8.000000 |
50% | 31.500000 | 205.000000 | 9.700000 | 79.000000 | 7.000000 | 16.000000 |
75% | 63.250000 | 258.750000 | 11.500000 | 85.000000 | 8.000000 | 23.000000 |
max | 168.000000 | 334.000000 | 20.700000 | 97.000000 | 9.000000 | 31.000000 |
列出DataFrame
的前五行:
df_1.head()
Ozone | Solar.R | Wind | Temp | Month | Day | |
---|---|---|---|---|---|---|
0 | 41 | 190 | 7.4 | 67 | 5 | 1 |
1 | 36 | 118 | 8.0 | 72 | 5 | 2 |
2 | 12 | 149 | 12.6 | 74 | 5 | 3 |
3 | 18 | 313 | 11.5 | 62 | 5 | 4 |
4 | NaN | NaN | 14.3 | 56 | 5 | 5 |
写
创建 CSV 文件的副本,以 UTF-8 编码并隐藏索引和标题标签:
代码语言:javascript复制df_1.to_csv('../data/ozone_copy.csv',
encoding='utf-8',
index=False,
header=False)
查看数据目录:
代码语言:javascript复制!ls -l ../data/
'''
total 1016
-rw-r--r-- 1 donnemartin staff 437903 Jul 7 2015 churn.csv
-rwxr-xr-x 1 donnemartin staff 72050 Jul 7 2015 confusion_matrix.png
-rw-r--r-- 1 donnemartin staff 2902 Jul 7 2015 ozone.csv
-rw-r--r-- 1 donnemartin staff 3324 Apr 1 07:18 ozone_copy.csv
drwxr-xr-x 10 donnemartin staff 340 Jul 7 2015 titanic
'''