Python数据分析笔记2 pandas基础


全面翻新的pandas介绍, 篇幅较长, 请善用右下角目录!

import numpy as np
import pandas as pd

数据结构

Series

Series(data=None, index=None, dtype=None, name=None, copy=False, , fastpath=False)
  • data: 可遍历序列数据
  • index: 索引, hsahable即可. 默认为从0开始的range
  • dtype: numpy.dtype数据类型
  • copy: 是否为data的副本(默认为视图, 对它的改动会直接反映到data上)
# 数组初始化
s = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
# 字典初始化
s = pd.Series({'d': 4, 'b':7, 'a':-5, 'c':3})
s
a   -5
b    7
c    3
d    4
dtype: int64
# 转换为numpy数组
s.values
array([-5,  7,  3,  4])
# 取出索引
s.index
Index(['a', 'b', 'c', 'd'], dtype='object')
# name属性: Series的name会自动继承于DataFrame的列名, Index的name会自动继承于Series的索引名
s.name = 'population'
s.index.name = 'state'

DataFrame

DataFrame(data=None, index=None, columns=None, dtype=None, copy=False)
  • data: 初始化方式和Series相似, 可以传入二维数组或者字典(key作为列名, value是等长数组)
  • columns: 列名. 字符串列表

其他参数和Series相似

# 初始化
df = pd.DataFrame(np.arange(16).reshape((4,4)),
index=['ohio','colorado', 'utah', 'new york'],
columns=['one', 'two', 'three', 'four'])
df
onetwothreefour
ohio0123
colorado4567
utah891011
new york12131415

索引对象

  1. 索引对象是不可改变的
  2. 索引的方法类似于集合操作: 包括diff, intersection, union, isin, drop, unique等

基本功能

reindex()

DataFrame.reindex(index=None, columns=None, **kwargs)
  • index: 重排的索引顺序
  • columns: 重排的列顺序(DataFrame独有)
  • method: 插值选项
  • fill_value: 插值时用于填充的值
  • limit: 最大填充量
  • level: 层次索引的层级
  • copy: 拷贝副本

drop()

DataFrame.drop(labels, axis=0, level=None, inplace=False, errors='raise')
  • labels: index列表或者column列表, 取决于axis是’index’还是’columns’
  • axis: 按行/列删除
  • level: 层次索引的层次
  • inplace: 就地删除

索引

Series的索引

# 取元素
s['a']
-5
# 切片, 注意切片是闭区间, 和数组不同
s['a':'c']
state
a   -5
b    7
c    3
Name: population, dtype: int64
# 花式索引
s[['c', 'a', 'b']]
state
c    3
a   -5
b    7
Name: population, dtype: int64

DataFrame的索引

# 取列
df['two']
ohio         1
colorado     5
utah         9
new york    13
Name: two, dtype: int64
# 取多列
df[['three', 'one']]
threeone
ohio20
colorado64
utah108
new york1412
# 按行切片
df[:2]
onetwothreefour
ohio0123
colorado4567
# 掩码
df[df['three'] > 5]
onetwothreefour
colorado4567
utah891011
new york12131415
# 索引切片
df.loc['colorado', ['three', 'one']]
three    6
one      4
Name: colorado, dtype: int64
# 数值索引切片
df.iloc[0:2, 1:3]
twothree
ohio12
colorado56

算数计算和数据对齐: add(), sub(), etc.

Series之间和DataFrame之间的运算

# 初始化
s1 = pd.Series([7.3, -2.5, 3.4, 1.5],
index=['a', 'c', 'd', 'e'])
s2 = pd.Series([-2.1, 3.6, -1.5, 4, 3.1],
index=['a', 'c', 'e', 'f', 'g'])
print(s1)
print(s2)
a    7.3
c   -2.5
d    3.4
e    1.5
dtype: float64
a   -2.1
c    3.6
e   -1.5
f    4.0
g    3.1
dtype: float64
# 加法会自动对齐索引, 不重叠的索引会引入nan
s1 + s2
a    5.2
c    1.1
d    NaN
e    0.0
f    NaN
g    NaN
dtype: float64
# 使用fill_value参数可以指定不重叠部分的默认填充值
s1.add(s2, fill_value=0)
a    5.2
c    1.1
d    3.4
e    0.0
f    4.0
g    3.1
dtype: float64
s1.add(s2, fill_value=1)
a    5.2
c    1.1
d    4.4
e    0.0
f    5.0
g    4.1
dtype: float64

DataFrame和Series的运算

DataFrame和Series做加减法时, 会将Series的索引匹配到DataFrame的列, 然后沿着行一直向下广播

df = pd.DataFrame(np.arange(12.).reshape((4, 3)),
columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon'])
s1 = df.loc['Utah'] # 一行
s2 = df.loc[:, 'd'] # 一列
print(df)
print(s1)
print(s2)
          b     d     e
Utah    0.0   1.0   2.0
Ohio    3.0   4.0   5.0
Texas   6.0   7.0   8.0
Oregon  9.0  10.0  11.0
b    0.0
d    1.0
e    2.0
Name: Utah, dtype: float64
Utah       1.0
Ohio       4.0
Texas      7.0
Oregon    10.0
Name: d, dtype: float64
# 匹配某一列, 然后沿着每一列广播
df.sub(s2, axis='index')
bde
Utah-1.00.01.0
Ohio-1.00.01.0
Texas-1.00.01.0
Oregon-1.00.01.0
# 匹配某一行, 然后沿着每一行传播
df.sub(s1, axis='columns')
bde
Utah0.00.00.0
Ohio3.03.03.0
Texas6.06.06.0
Oregon9.09.09.0

函数和映射: apply()

apply可以作用到每个元素, 或者应用到各行各列形成的一维数组上

df = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon'])
df
bde
Utah-0.1831650.160413-0.774075
Ohio2.2411140.9283370.035367
Texas0.811800-1.106693-0.355058
Oregon0.3949041.499819-0.235244
f = lambda x: x.max() - x.min()
# 作用到一列形成的一维数组(默认)
df.apply(f, axis='index')
b    2.424278
d    2.606512
e    0.809443
dtype: float64
# 作用到一行形成的一维数组
df.apply(f, axis='columns')
Utah      0.934488
Ohio      2.205746
Texas     1.918493
Oregon    1.735063
dtype: float64
# 作用到每个元素. map是属于Series的
f = lambda x: "%.2f" % (x)
df.applymap(f)
bde
Utah-0.180.16-0.77
Ohio2.240.930.04
Texas0.81-1.11-0.36
Oregon0.391.50-0.24
# 形成多个统计值
def f(x):
return pd.Series([x.min(), x.max()], index=['min', 'max'])
# 沿着索引统计每一列
df.apply(f, axis='index')
bde
min-0.183165-1.106693-0.774075
max2.2411141.4998190.035367
# 沿着列统计每一行
df.apply(f, axis='columns')
minmax
Utah-0.7740750.160413
Ohio0.0353672.241114
Texas-1.1066930.811800
Oregon-0.2352441.499819

排序

按索引排序: sort_index()

默认是按升序排列, 参数ascending可以改为降序

# Series按索引排序
s = pd.Series(range(4), index=['d', 'a', 'b', 'c'])
s.sort_index()
a    1
b    2
c    3
d    0
dtype: int64
# DataFrame按索引和列排序. 通过axis参数选择按索引还是列排序
df = pd.DataFrame(np.arange(8).reshape((2, 4)),
index=['three', 'one'],
columns=['d', 'a', 'b', 'c'])
# 按索引排序(默认)
df.sort_index(axis='index')
dabc
one4567
three0123
# 按列排序
df.sort_index(axis='columns')
abcd
three1230
one5674

按值排序: sort_values()

  1. 通过by选择某一列
  2. NaN会排在最后
# Series按值排序
s = pd.Series([4, np.nan, -3, 2])
s.sort_values()
2   -3.0
3    2.0
0    4.0
1    NaN
dtype: float64
# DataFrame按值排序, 通过by参数选择列
df = pd.DataFrame({'b': [4, 7, -3, 2], 'a': [0, 1, 0, 1]})
df.sort_values(by=['a', 'b'])
ab
20-3
004
312
117

排名: rank()

  1. 通过axis参数选择按索引还是列排名
  2. 通过method选择排名方法
# DataFrame按值rank, 通过axis参数选择按索引还是列计算排名
df.rank(method='first', axis='index')
ab
01.03.0
13.04.0
22.01.0
34.02.0

汇总和计算描述统计

求和: Sum()

sum(axis=None, skipna=None, level=None, numeric_only=None, **kwargs)
  • axis: 沿着索引还是列求和
  • skipna: 是否排除NaN. 若不排除, 只要有NaN, 和就为NaN
  • level: 层次索引的层次

其他平均数, 中位数, 方差, 标准差等方法类似

相关系数和协方差

corr(method='pearson', min_periods=1)
  • method : {‘pearson’, ‘kendall’, ‘spearman’}, 协方差计算公式
  • min_periods : 可选, 最小样本数

两个Series的相关系数和协方差的计算, 满足:

  1. 按索引对齐
  2. 索引重叠
  3. 非NaN

DataFrame的协方差和相关系数会直接返回协方差矩阵:

Compute pairwise correlation of columns, excluding NA/null values

# 按列配对计算协方差
df.corr()
ab
a1.0000000.549442
b0.5494421.000000
# 计算b列与df中每一列的协方差
df.corrwith(df.b)
a    0.549442
b    1.000000
dtype: float64

unique, value_counts和isin

Series.unique()

返回Series的唯一值序列

Series.value_counts(normalize=False, sort=True, ascending=False, bins=None, dropna=True)
  • normalize: 用频率替换频度
  • sort: 按频率排序
  • ascending: 升/降序排列, 默认是降序
  • bins: 自动划分阈值, 将数值类数据分为bins块
  • dropna: 去掉NaN
s = pd.Series([7,3,2,2,5,6,6,5,9])
s.value_counts(bins=2)
(1.992, 5.5]    5
(5.5, 9.0]      4
dtype: int64
DataFrame.isin(values)
  • values: 数值列表
    返回masked DataFrame, 在values中的为True, 否则为False
  1. 当values为序列时, 很显然
  2. 当values为字典时, DataFrame的列匹配key, 值匹配value
  3. 当values为DataFrame时, 相当于掩码, 见以下例子
df = pd.DataFrame({'A': [1, 2, 3], 'B': ['a', 'b', 'f']})
other = pd.DataFrame({'A': [1, 3, 3, 2], 'B': ['e', 'f', 'f', 'e']})
print(df)
print(other)
   A  B
0  1  a
1  2  b
2  3  f
   A  B
0  1  e
1  3  f
2  3  f
3  2  e
df.isin(other)
AB
0TrueFalse
1FalseFalse
2TrueTrue

处理缺失数据

dropna()

DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
  • axis: {‘index’, ‘columns’}, 丢掉含有NaN的行/列, 默认为行
  • how: {‘any’, ‘all’}, 只要有NaN就丢弃还是全NaN才丢弃
  • thresh: 大于等于多少个NaN就丢弃
  • subset: 如果丢弃行, 这就是一个列名的列表, 处于这个列表中的列才会计入NaN
  • inplace: 就地丢弃

fillna()

DataFrame.fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None, **kwargs)

参数不解释了, 只提一下value还可以是dict, Series, 乃至DataFrame, 填充方式与掩码相似

层次化索引

index是可以使用多组数组的, 代表了不同层次的索引

# 初始化层次索引
s = pd.Series(np.random.randn(10),
index=[['a','a','a','b','b','b','c','c','d','d'],
[1,2,3,1,2,3,1,2,2,3],
[9,8,7,9,8,7,9,8,8,7]])
s
a  1  9    0.320638
   2  8   -0.666312
   3  7   -0.549029
b  1  9   -0.375222
   2  8    0.942717
   3  7    0.588951
c  1  9    2.538862
   2  8   -1.635290
d  2  8   -1.602510
   3  7    0.187961
dtype: float64
# 索引属于MultiIndex类
s.index
MultiIndex(levels=[['a', 'b', 'c', 'd'], [1, 2, 3], [7, 8, 9]],
           labels=[[0, 0, 0, 1, 1, 1, 2, 2, 3, 3], [0, 1, 2, 0, 1, 2, 0, 1, 1, 2], [2, 1, 0, 2, 1, 0, 2, 1, 1, 0]])

层次化索引方式

s['a']
1  9    0.320638
2  8   -0.666312
3  7   -0.549029
dtype: float64
s['b':'c']
b  1  9   -0.375222
   2  8    0.942717
   3  7    0.588951
c  1  9    2.538862
   2  8   -1.635290
dtype: float64
s[['b', 'd']]
b  1  9   -0.375222
   2  8    0.942717
   3  7    0.588951
d  2  8   -1.602510
   3  7    0.187961
dtype: float64
# 这里代表了第一层和第二层索引, 而不是行和列
s[:, 2]
a  8   -0.666312
b  8    0.942717
c  8   -1.635290
d  8   -1.602510
dtype: float64

转化为DataFrame: unstack()

将最内层的索引变成新的列名, 形成新的DataFrame

# 拆分
s.unstack()
789
a1NaNNaN0.320638
2NaN-0.666312NaN
3-0.549029NaNNaN
b1NaNNaN-0.375222
2NaN0.942717NaN
30.588951NaNNaN
c1NaNNaN2.538862
2NaN-1.635290NaN
d2NaN-1.602510NaN
30.187961NaNNaN
# 聚合
s.unstack().stack()
a  1  9    0.320638
   2  8   -0.666312
   3  7   -0.549029
b  1  9   -0.375222
   2  8    0.942717
   3  7    0.588951
c  1  9    2.538862
   2  8   -1.635290
d  2  8   -1.602510
   3  7    0.187961
dtype: float64

重排层次顺序: swaplevel()

# 交换两个index的层次顺序
swaplevel(indexName1, indexName2)

根据级别汇总统计

参考Sum()level参数

使用DataFrame的列

# 初始化并命名索引
df = s.unstack()
df.index.names = ['index1', 'index2']
df
789
index1index2
a1NaNNaN0.320638
2NaN-0.666312NaN
3-0.549029NaNNaN
b1NaNNaN-0.375222
2NaN0.942717NaN
30.588951NaNNaN
c1NaNNaN2.538862
2NaN-1.635290NaN
d2NaN-1.602510NaN
30.187961NaNNaN

将列转换为索引: set_index()

# 把7,8两列变成索引
df.set_index([7, 8])
9
78
NaNNaN0.320638
-0.666312NaN
-0.549029NaNNaN
NaNNaN-0.375222
0.942717NaN
0.588951NaNNaN
NaNNaN2.538862
-1.635290NaN
-1.602510NaN
0.187961NaNNaN

将索引转换为列: reset_index()

# 把'index1', 'index2'两个索引变成列
df.reset_index(['index1', 'index2'])
index1index2789
0a1NaNNaN0.320638
1a2NaN-0.666312NaN
2a3-0.549029NaNNaN
3b1NaNNaN-0.375222
4b2NaN0.942717NaN
5b30.588951NaNNaN
6c1NaNNaN2.538862
7c2NaN-1.635290NaN
8d2NaN-1.602510NaN
9d30.187961NaNNaN