pandas库提供了高性能、易于使用的数据结构和数据分析工具。其主要数据结构是DataFrame,可以将DataFrame看做内存中的二维表格,如带有列名和行标签的电子表格。许多在Excel中可用的功能都可以通过编程实现,例如创建数据透视表、基于其他列计算新列的值、绘制图形等。还可以按照列的值对行进行分组,或者像SQL中那样连接表格。pandas也擅长处理时间序列。
但是介绍pandas之前,需要有numpy的基础,如果还不熟悉numpy,可以查看numpy快速入门教程。
导入pandas
import pandas as pd
一个DataFrame对象表示一个电子表格,带有单元格值、列名和行索引标签。可以定义表达式基于其他列计算列的值、创建数据透视表、按行分组、绘制图形等。可以将DataFrame视为Series的字典。
grades_array = np.array([[8, 8, 9], [10, 9, 9], [4, 8, 2], [9, 10, 10]])
grades = pd.DataFrame(grades_array, columns=['sep', 'oct', 'nov'], index=['alice', 'bob', 'charles', 'darwin'])
grades
输出:
和Series相似,当操作多个DataFrame时,pandas会根据行索引标签自动对齐,但是也会按列名对齐。现在创建一个DataFrame,在10-12月每个人的奖励积分。
bonus_array = np.array([[0, np.nan, 2], [np.nan, 1, 0], [0, 1, 0], [3, 3, 0]])
bonus_points = pd.DataFrame(bonus_array, columns=['oct', 'nov', 'dec'], index=['bob', 'colin', 'darwin', 'charles'])
bonus_points
输出:
bonus_points + grades
输出:
在处理真实数据时,处理缺失数据是一项常见的任务。pandas提供了一些处理缺失数据的工具。
现在解决上面的问题,例如可以决定将缺失值设置为0,而不是NaN。可以使用fillna()方法,将所有的NaN值替换为任意值。
(bonus_points + grades).fillna(0)
输出:
但是,在9月份将分数设为0有点不公平。或许应该确定缺失的分数就是缺失的分数,但是缺失的积分奖励应该被0替代。
fixed_bonus_points = bonus_points.fillna(0) # 将积分奖励的缺失值替换为0
fixed_bonus_points.insert(0, 'sep', 0) # 添加九月份一列
fixed_bonus_points.loc['alice'] = 0 # 添加alice一行
grades + fixed_bonus_points
输出:
这样处理之后结果就好得多,虽然制造了一些数据,但是没有太不公平。
处理缺失值的另一种方法是插值。现在我们在看一下积分奖励DataFrame。
bonus_points
输出:
现在调用interpolate()方法,默认情况下,它是垂直插值,即axis=0,现在设置水平插值,axis=1。
bonus_points.interpolate(axis=1)
输出:
水平插值处理缺失值时,bob在10月份为0分,12月份为2分,对11月份插值时会得到平均值1分。colin在11月份为1分,但是不知道他在九月份的奖励分,所以无法插值,这就是为什么插值后10月份仍然缺少一个值。为了解决这个问题,可以在插值之前将9月份的奖励分设置为0。
better_bouns_points = bonus_points.copy()
better_bouns_points.insert(0, 'sep', 0)
better_bouns_points.loc['alice'] = 0
better_bouns_points = better_bouns_points.interpolate(axis=1)
better_bouns_points
输出:
现在有合理的奖励积分了,再看看最后的成绩。
better_bouns_points + grades
输出:
上面的结果中,9月份出现了右边,这有点不太满意。这是因为我们添加的DataFrame没有完全相同的列, 即grades缺少dec列,所以pandas按字母顺序排序了列。解决这个问题,只需要在添加之前,添加缺少的列即可,即在grades中添加dec列。
grades['dec'] = np.nan
final_grades = better_bouns_points + grades
final_grades
输出:
对于12月份列和colin行, 可以考虑使用dropna()方法,去除充满NaN的行或列。
final_grades_clean = final_grades.dropna(axis=0, how='all') # 删除整行均为NaN的行
final_grades_clean
输出:
final_grades_clean = final_grades_clean.dropna(axis=1, how='all') # 删除整列均为NaN的列
final_grades_clean
输出:
与SQL语言相似,pandas允许将数据进行分组,以便在每组上进行运算。
首先,在final_grades添加一些关于每个人的额外数据,以便可以对他们分组。然后,再回到final_grades,看一下NaN值是如何处理的。
final_grades['hobby'] = ['Biking', 'Dancing', np.nan, 'Dancing', 'Biking']
final_grades
输出:
现在,按hobby将DataFrame进行分组。
grouped_grades = final_grades.groupby(by='hobby')
grouped_grades
输出:
按hobby进行分组后,计算每个hobby的平均值。
grouped_grades.mean()
输出:
根据上面的结果,在计算平均值时,NaN值被跳过了。
pandas支持类似电子表格的数据透视表, 可以快速汇总数据。
现在在bonus_poins的基础上创建一个新的DataFrame,来介绍数据透视表。
bonus_points
输出:
more_grades = final_grades_clean.stack().reset_index()
more_grades.columns = ['name', 'month', 'grade']
more_grades['bonus'] = [np.nan, np.nan, np.nan, 0, np.nan, 2, 3, 3, 0, 0, 1, 0]
more_grades
输出:
对上面的DataFrame调用pandas的pivot_table()函数,要求按name列进行分组。默认情况下,pivot_table()函数计算每个数值列的平均值。
pd.pivot_table(more_grades, index='name')
输出:
可以通过设置aggfunc参数来更改聚合函数,还可以指定要聚合哪些列的值。
pd.pivot_table(more_grades, index='name', aggfunc=np.max, values=['grade', 'bonus'])
输出:
还可以指定要横向聚合的列,并通过设置margins=True来计算每行和每列的总平均值。
pd.pivot_table(more_grades, index='name', values='grade', columns='month', margins=True)
输出:
还可以指定多个索引或列名,pandas将创建多级索引。
pd.pivot_table(more_grades, index=('name', 'month'), margins=True)
输出:
在处理大型DataFrame时,快速了解其内容非常有用。pandas提供了一些可以预览DataFrame的函数。
先创建一个包含数值、缺失值和文本值的大型DataFrame。
much_data = np.fromfunction(lambda x, y: (x+y*y)%17*11, (10000, 26))
large_df = pd.DataFrame(much_data, columns=list('ABCDEFGHIJKLMNOPQRSTUVWXYZ'))
large_df[large_df % 16 == 0] = np.nan
large_df.insert(3, 'some_text', 'Blala')
large_df
输出:10000×27 大小的DataFrame,由于数据量大这里不做显示。
方法head()默认查看前5行,可以修改要查看的行数。
large_df.head()
输出:
large_df.head(3)
输出:
方法tail()默认查看后5行,也可以修改要查看的行数。
large_df.tail(2)
输出:
方法info()是返回每一列内容的概况。
large_df.info()
输出:
RangeIndex: 10000 entries, 0 to 9999
Data columns (total 27 columns):
A 8823 non-null float64
B 8824 non-null float64
C 8824 non-null float64
some_text 10000 non-null object
D 8824 non-null float64
E 8822 non-null float64
F 8824 non-null float64
G 8824 non-null float64
H 8822 non-null float64
I 8823 non-null float64
J 8823 non-null float64
K 8822 non-null float64
L 8824 non-null float64
M 8824 non-null float64
N 8822 non-null float64
O 8824 non-null float64
P 8824 non-null float64
Q 8824 non-null float64
R 8823 non-null float64
S 8824 non-null float64
T 8824 non-null float64
U 8824 non-null float64
V 8822 non-null float64
W 8824 non-null float64
X 8824 non-null float64
Y 8822 non-null float64
Z 8823 non-null float64
dtypes: float64(26), object(1)
memory usage: 2.1+ MB
describe()方法可以很好地概述每列上的主要聚合值。
large_df.describe()
输出(部分显示):