上一节介绍了numpy,这篇介绍下pandas
2.2 pandas库基础

pandas库是基于NumPy库的一个开源Python库,广泛应用于完成数据快速分析、数据清洗和准备等工作,它的名字来源于“paneldata”(面板数据)。pandas库提供了非常直观的数据结构及强大的数据管理和数据处理 功能,某种程度上可以把pandas库看成Python版的Excel。pandas库也是Anaconda自带的,无须单独安装。

与NumPy库相比,pandas库更擅长处理二维数据。

pandas库主要有Series和DataFrame两种数据结构

Series类似于通过NumPy库创建的一维数组,不同的是Series对象不仅包含数值,还包含一组索引,其创建方式如下。

 import pandas as pd
 s1 = pd.Series(['丁一', '王二', '张三'])
 0    丁一
 1    王二
 2    张三
 dtype: object

s1的打印输出结果如下,它也是一个一维数据结构,并且每个元素都有一个可以用来定位的行索引,例如,可以通过s1[1]来定位到第2个元素“王二”。

Series单独使用相对较少,我们学习pandas库主要是为了使用它提供的DataFrame数据结构。

DataFrame是一种二维表格数据结构,可以将其看成一个Excel表格。

2.2.1 二维数据表格DataFrame的创建

DataFrame可以通过列表、字典或二维数组创建,下面分别介绍具体创建方法。

1.通过列表创建DataFrame
  • 引入pandas库的方式通常为“import pandas as pd”,然后调用DataFrame()函数创建DataFrame,代码如下。
import pandas as pd
a = pd.DataFrame([[1, 2], [3, 4], [5, 6]])
print(a)   # 在Jupyter Notebook中也可以直接输入变量名a来查看

    0  1
 0  1  2
 1  3  4
 2  5  6

和之前通过NumPy库创建的二维数组进行比较。

1 [[1 2]
2  [3 4]
3  [5 6]]

用pandas库的DataFrame()函数创建的DataFrame更像Excel中的二维表格数据,它也有行索引和列索引。需要注意的是,这里的索引序号是从0开始的。

我们还可以在创建DataFrame时自定义列索引和行索引的名称,代码如下。

a = pd.DataFrame([[1, 2], [3, 4], [5, 6]], columns=['date', 'score'],
index=['A', 'B', 'C'])

	date	score
A	1	2
B	3	4
C	5	6

  • 通过列表创建DataFrame还可以采用如下方式。
a = pd.DataFrame()  # 创建一个空DataFrame
date = [1, 3, 5]
score = [2, 4, 6]
a['date'] = date
a['score'] = score

date	score
0	1	2
1	3	4
2	5	6

注意要保证date列表和score列表的长度一致,否则会报错

这种方法在汇总特征变量名称及特征重要性时会有应用。

2.通过字典创建DataFrame
  • 除了通过列表创建DataFrame,还可以通过字典创建DataFrame,并可以自定义列索引,这里默认字典键为列索引,代码如下。
import pandas as pd
b = pd.DataFrame({'a': [1, 3, 5], 'b': [2, 4, 6]}, index=['x', 'y', 'z'])
print(b)  # 在Jupyter Notebook中也可以直接输入变量名b来查看

   a  b
x  1  2
y  3  4
z  5  6

可以看到列索引已经变成了字典里的键名

  • 如果想让字典键变成行索引,可以使用from_dict()函数将字典转换成DataFrame,并同时设置orient参数为index,代码如下。
 c = pd.DataFrame.from_dict({'a': [1, 3, 5], 'b': [2, 4, 6]}, orient
="index")
print(c)

   0  1  2
a  1  3  5
b  2  4  6

其中orient参数用于指定字典键为列索引还是行索引,默认值为columns,即默认字典键为列索引,如果设置成index,则表示字典键为行索引

  • 除了使用from_dict()函数的orient参数外,还可以通过DataFrame的T属性对DataFrame进行转置,演示代码如下:
b = pd.DataFrame({'a': [1, 3, 5], 'b': [2, 4, 6]})
print(b)  # 打印原始表格
print(b.T)  # 打印转置后的表格

   a  b
0  1  2
1  3  4
2  5  6
   0  1  2
a  1  3  5
b  2  4  6

可以看到b.T是b的转置。需要注意的是,如果想改变原来的表格结构,需要进行重新赋值,写成b=b.T。

3.通过二维数组创建DataFrame

在NumPy库创建的二维数组的基础上,也可以创建DataFrame。这里以2.1.3小节中创建的二维数组为基础,创建一个3行4列的DataFrame,代码如下。

import numpy as np, pandas as pd
d = pd.DataFrame(np.arange(12).reshape(3, 4), index=[1, 2, 3], columns
=['A', 'B', 'C', 'D'])
d

	A	B	C	D
1	0	1	2	3
2	4	5	6	7
3	8	9	10	11

补充知识点:修改行索引或列索引名称若要修改行索引或列索引的名称,可以使用rename()函数。先构造一个DataFrame,代码如下。

 a = pd.DataFrame([[1, 2], [3, 4]], columns=['date', 'score'],
index=['A', 'B'])
     date  score
 A      1      2
 B      3      4

接着使用rename()函数重命名索引,代码如

a = a.rename(index={'A':'阿里', 'B':'腾讯'}, columns={'date':'日期',
'score':'分数'})

rename()函数是用新索引名新建一个DataFrame,未改变a的内容,所以这里将新DataFrame赋给a来改变其内容。也可以设置inplace参数为True来实现真正的重命名,代码如下。

a.rename(index={'A':'阿里', 'B':'腾讯'}, columns={'date':'日期',
'score':'分数'}, inplace=True)
	日期	分数
阿里	1	2
腾讯	3	4

通过values属性可以查看此时的index值,代码如下。

a.index.values

它是一个array格式的一维数它是一个array格式的一维数

 ['阿里' '腾讯']

如果想把行索引修改成某列的内容,可以使用set_index()函数,代码如下。

 a = a.set_index('日期')

	分数
日期	
1	2
3	4

和rename()函数一样,set_index()函数也可以设置inplace参数为True,这样就不用进行重新赋值,代码如下

a.set_index('日期', inplace=True)

如果此时想把行索引换成数字索引,可以使用reset_index()函数,代码如下。

 a = a.reset_index()

此时a的打印输出结果如下,可以看到行索引变成数字,原行索引变成新的一列。

    日期  分数
 0   1   2
 1   3   4
2.2.2 Excel工作簿等文件的读取和写入

通过pandas库可以从多种数据文件中读取数据,也可以将获得的数据写入这些文件中。

本小节以Excel工作簿和CSV文件为例讲解如何进行文件的读取和写入。

1.文件的读取

以下代码用于读取Excel工作簿中的数据。

 import pandas as pd
 data = pd.read_excel('data.xlsx')  # data为DataFrame结构

这里的Excel工作簿文件扩展名为.xlsx,2003版或更早版本的Excel工作簿文件,其扩展名为.xls。这里使用的文件路径是相对路径,即代码文件所在的文件夹,也可以设置成绝对路径(相关知识见本小节的“补充知识点”)。

通过打印data便可以查看读取到的表格内容,也可以使用data.head()函数打印表格的前5行内容,代码如下。如果写成data.head(10),则可以打印前10行内容,依此类推。

 data.head()  # 非Jupyter Notebook编辑器需要通过print()函数打印,下同

read_excel()函数还可以设定更多参数,演示代码如下

 data = pd.read_excel('data.xlsx', sheet_name=0, encoding='utf-8')

sheet_name用于指定要读取的工作表,可以是工作表名称,也可以是数字(默认为0,即第1个工作表);encoding用于指定文件编码方式,一般设置为“utf-8”或“gbk”,以避免中文乱码;index_col用于设置某一列为行索引。

  • 除了读取Excel工作簿,pandas库还可以读取CSV文件。CSV文件本质上是一个文本文件,它仅存储数据,不能像Excel工作簿那样存储格式、公式、宏等信息,所以所占存储空间通常较小。CSV文件一般用逗号分隔一系列值,既可以用Excel打开,也可以用文本编辑器(如“记事本”)打开。
1 data = pd.read_csv('data.csv')

read_csv()函数也可以设定更多参数,演示代码如下。

data = pd.read_csv('data.csv', delimiter=',', encoding='utf-8')

delimiter参数用于指定CSV文件中的分隔符号,默认为逗号;encoding参数用于指定编码方式,一般设置为“utf-8”或“gbk”,以避免中文乱码。此外,read_csv()函数也可以通过index_col参数设置索引列。

2.文件的写入

以下代码可以将数据写入Excel工作簿。

 # 先创建一个DataFrame
 data = pd.DataFrame([[1, 2], [3, 4], [5, 6]], columns=['A列', 'B列'])
 # 将DataFrame中的数据写入Excel工作簿
 data.to_excel('data_new.xlsx')

这里的文件存储路径使用的是相对路径,可以根据需要写成绝对路径。运行之后将在代码文件所在的文件夹生成一个“data_new.xlsx”文件

在上图中,行索引信息保留在工作表的第1列中,如果想在写入数据时不保留行索引信息,可以设置to_excel()函数的参数。常用参数有:sheet_name用于指定工作表名称;index用于指定是否写入行索引信息,默认为True,即将行索引信息写入输出文件的第1列,若设置为False,则忽略行索引信息;columns用于指定要写入的列;encoding用于指定编码方式。

要将data中的A列数据写入Excel工作簿并忽略行索引信息,则代码如下。

data.to_excel('data_new.xlsx', columns=['A列'], index=False)

通过类似的方式,可以将data中的数据写入CSV文件,代码如下。

data.to_csv('data_new.csv')

和to_excel()函数类似,to_csv()函数也可以设置index、columns、encoding等参数。需要注意的是,如果生成的CSV文件中有中文乱码现象,且设置encoding参数为“utf-8”失效,则需要设置encoding参数为“utf_8_sig”,代码如下。

 data.to_csv('演示.csv', index=False, encoding="utf_8_sig")

补充知识点:文件相对路径与绝对路径

  • 相对路径

相对路径即代码文件所在的文件夹。例如,data.to_excel('data.xlsx')就是在代码文件所在的文件夹中生成Excel工作簿。·

  • 绝对路径

绝对路径即文件的完整路径。例如,“E:\大数据分析\data.xlsx”就是绝对路径。要注意的是,在Python中反斜杠“\”有特殊含义,如“\n”表示换行符,所以写绝对路径时通常建议用两个反斜杠取消单个反斜杠的特殊含义。例如,写成“E:\\大数据分析\\data.xlsx”。除了用两个反斜杠来取消单个反斜杠的特殊含义外,在文件路径的字符串前面加一个“r”,也可以取消单个反斜杠的特殊含义,演示代码如下。

1  data.to_excel('E:\\大数据分析\\data.xlsx')  # 绝对路径推荐写法1,此
时E盘要有一个名为“大数据分析”的文件夹
2  data.to_excel(r'E:\大数据分析\data.xlsx')  # 绝对路径推荐写法2,此
时E盘要有一个名为“大数据分析”的文件夹
 import pandas as pd
 file_path = 'F:/JupyterNotebooks/data.xlsx'
 data = pd.read_excel(file_path)  # data为DataFrame结构
 data.head() 
2.2.3 数据的选取与处理

首先创建一个3行3列的DataFrame用于演示,行索引设定为r1、r2、r3,列索引设定为c1、c2、c3,代码如下。

import pandas as pd
data = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]], index=['r1',
'r2', 'r3'], columns=['c1', 'c2', 'c3'])

也可以用2.2.1小节中介绍的方法,通过二维数组创建DataFrame。这里以数字1为起点,数字10为终点(终点取不到),生成1~9共9个数字,作为DataFrame中的数据,代码如下。

data = pd.DataFrame(np.arange(1, 10).reshape(3, 3), index=['r1',
'r2', 'r3'], columns=['c1', 'c2', 'c3'])

两种方法得到的data是一样的,打印输出结果如下。

     c1  c2  c3
 r1   1   2   3
 r2   4   5   6
 r3   7   8   9

接下来就以上面创建的data为例,讲解数据的选取、筛选、整体情况查看、运算、排序与删除等知识点。

1.数据选取

(1)按列选取数据先从简单的选取单列数据入手,代码如下。

 a = data['c1']
r1    1
r2    4
r3    7
Name: c1, dtype: int64

可以看到选取的数据不包含列索引信息,这是因为通过data['c1']选取一列时返回的是一个一维的Series类型的数据。通过如下代码可以返回一个二维的表格数据。

b = data[['c1']]
     c1
 r1   1
 r2   4
 r3   7

若要选取多列,需要在中括号[]中指定列表。例如,要选取c1和c3列,可以写为data[['c1','c3']]。需要注意的是,中括号[]中必须是一个列表,而不能是data['c1','c3']。代码如下。

 c = data[['c1', 'c3']]

(2)按行选取数据

可以根据行序号来选取数据,代码如下。

 # 选取第2~3行的数据,注意序号从0开始,左闭右开
 a = data[1:3]

      c1  c2  c3
 r2   4   5   6
 r3   7   8   9

pandas库推荐使用iloc方法来根据行序号选取数据,这样更直观,不会像data[1:3]那样可能会引起混淆。代码如下。

 b = data.iloc[1:3]

如果要选取单行,就必须用iloc方法。例如,选取倒数第1行,代码如下。

c = data.iloc[-1]

此时如果使用data[-1],则程序可能会认为-1是列名,导致混淆报错。

除了根据行序号选取数据外,还可以通过loc方法根据行的名称来选取数据,代码如下。

d = data.loc[['r2', 'r3']]

如果行数很多,可以通过head()函数选取前5行数据,代码如下。

 e = data.head()

这里因为data中只有3行数据,所以通过head()函数会选取全部数据。如果只想选取前两行数据,可以写成data.head(2)。

(3)按区块选取数据

如果想选取某几行的某几列数据,例如,选取c1和c3列的前两行数据,代码如下。

a = data[['c1', 'c3']][0:2]  # 也可写成data[0:2][['c1', 'c3']]

     c1  c3
 r1   1   3
 r2   4   6

其实就是把前面按行和列选取数据的方法进行了整合

在实战中选取区块数据时,通常先通过iloc选取行,再选取列,代码如下。

 b = data.iloc[0:2][['c1', 'c3']]

两种方法的选取效果是一样的,但第二种方法逻辑更清晰,代码不容易混淆,它也是pandas库的官方文档推荐的方法。

如果要选取单个值,该方法就更有优势。例如,选取c3列第1行的数据,就不能写成data['c3'][0]或data[0]['c3'],而要先用iloc[0]选取第1行,再选取c3列,代码如下。

c = data.iloc[0]['c3']

也可以使用iloc和loc方法同时选取行和列,代码如下。

1 d = data.loc[['r1', 'r2'], ['c1', 'c3']]
2 e = data.iloc[0:2, [0, 2]]

     c1  c3
 r1   1   3
 r2   4   6

需要注意的是,loc方法使用字符串作为索引,iloc方法使用数字作为索引。有个简单的记忆方法:loc是location(定位、位置)的缩写,所以是用字符串作为索引;iloc中多了一个字母i,而i又经常代表数字,所以是用数字作为索引。d和e的打印输出结果如下。

选取区块数据还有一个ix方法,它的索引不像loc或iloc必须为字符串索引或数字索引,代码如下。

 f = data.ix[0:2, ['c1', 'c3']]

其操作逻辑和效果与data.iloc[0:2][['c1','c3']]一样,但pandas库目前已经不推荐使用ix,所以之后需要选取区块数据时,还是以data.iloc[0:2][['c1','c3']]方式为主。

2.数据筛选

通过在中括号里设定筛选条件可以过滤行。例如,筛选c1列中数字大于1的行,代码如下。

a = data[data['c1'] > 1]

     c1  c2  c3
 r2   4   5   6
 r3   7   8   9

如果有多个筛选条件,可以通过“&”(表示“且”)或“|”(表示“或”)连接。例如,筛选c1列中数字大于1且c2列中数字小于8的行,代码如下。注意在筛选条件两侧要加上小括号。此外,判断两者是否相等是用“==”,而不是“=”(一个等号表示赋值,两个等号表示逻辑判断)。

b = data[(data['c1'] > 1) & (data['c2'] < 8)]

     c1  c2  c3
 r2   4   5   6
3.数据整体情况查看

通过DataFrame的shape属性可以获取表格整体的行数和列数,从而快速了解表格的数据量大小。

data.shape
 (3, 3)

运行结果如下,其中第1个数字为表格行数,第2个数字为表格列数。

通过describe()函数可以快速查看表格每一列的数据个数、平均值、标准差、最小值、25分位数、50分位数、75分位数、最大值等信息,代码如下。

 data.describe()

 	c1	c2	c3
count	3.0	3.0	3.0
mean	4.0	5.0	6.0
std	3.0	3.0	3.0
min	1.0	2.0	3.0
25%	2.5	3.5	4.5
50%	4.0	5.0	6.0
75%	5.5	6.5	7.5
max	7.0	8.0	9.0

通过value_counts()函数可以快速查看某一列有几种数据,以及每种数据出现的频次,代码如下。

 data['c1'].value_counts()

运行结果如下,可以看到c1列共有3种不同的数据,且每种数据出现的频次为1。

 7    1
 1    1
 4    1
 Name: c1, dtype: int64

这些知识点在查看电影评分数据时会有应用。

4.数据的运算、排序与删除

(1)数据运算

从已有的列中,通过数据运算创建新的一列,代码如下。

 data['c4'] = data['c3'] - data['c1']
 data.head()

      c1  c2  c3  c4
 r1   1   2   3   2
 r2   4   5   6   2
 r3   7   8   9   2

其中data.head()是输出表格的前5行,由于表格只有3行,所以全部输出。

(2)数据排序

使用sort_values()函数可以对表格按列排序。例如,按c2列进行降序排序的代码如下。

a = data.sort_values(by='c2', ascending=False)
     c1  c2  c3  c4
 r3   7   8   9   2
 r2   4   5   6   2
 r1   1   2   3   2

by参数用于指定按哪一列来排序;ascending参数默认为True,表示升序排序,若设置为False则表示降序排序。a的打印输出结果如下。

按列排序也可以不写“by=”,效果一样,代码如下

 a = data.sort_values('c2', ascending=False)

使用sort_index()函数可以根据行索引进行排序。例如,按行索引进行升序排序的代码如下。

 a = a.sort_index()

运行代码后,则前面按c2列降序排序后生成的a表格的行索引又变成r1、r2、r3的升序排序形式了。同样也可以设置ascending参数为False来进行降序排序。

该知识点在按序查看变量特征的重要性时会有应用。

(3)数据删除

使用drop()函数可以删除表格中的指定数据,具体用法如下。

 DataFrame.drop(index=None, columns=None, inplace=False)

drop函数常用的几个参数解释如下:index用于指定要删除的行;columns用于指定要删除的列;inplace默认为False,表示该删除操作不改变原表格,而是返回一个执行删除操作后的新表格,如果设置inplace为True,则会直接在原表格中执行删除操作。

若要删除单列数据,例如,删除c1列的数据,代码如下。

a = data.drop(columns='c1')

若要删除多列数据

b = data.drop(columns=['c1', 'c3'])

若要删除行数据,例如,删除第1行和第3行,代码如下。

 c = data.drop(index=['r1', 'r3'])

需要注意的是,上述代码中要输入行索引的名称而不是数字序号,除非行索引名称本来就是数字,才可以输入对应的数字。上述代码将删除数据后的表格又赋给新的变量,不会改变原表格data的结构,如果想改变原表格data的结构,可以设置inplace参数为True,代码如下。

 data.drop(index=['r1', 'r3'], inplace=True)

该知识点在处理重复值时会有应用。

2.2.4 数据表拼接

pandas库还提供了一些高级功能,其中的数据合并与重塑为两个数据表的拼接提供了极大的便利,主要涉及merge()、concat()、append()等函数,下面通过一个例子进行简单介绍。假设创建了如下两个DataFrame数据表,需要将它们合并。

import pandas as pd
df1 = pd.DataFrame({'公司': ['万科', '阿里', '百度'], '分数': [90.0,
95.0, 85.0]})
df2 = pd.DataFrame({'公司': ['万科', '阿里', '京东'], '股价': [20.0,
180.0, 30.0]})
df1
df2

公司	分数
0	万科	90.0
1	阿里	95.0
2	百度	85.0

	公司	股价
0	万科	20.0
1	阿里	180.0
2	京东	30.0
1.merge()函数

merge()函数可以根据一个或多个键(列)将不同数据表中的行连接起来,演示代码如下。

 df3 = pd.merge(df1, df2)

 	公司	分数	股价
0	万科	90.0	20.0
1	阿里	95.0	180.0

可以看到,merge()函数直接根据相同的列名(“公司”列)对两个表进行了合并,而且默认选取的是两个表共有的列内容(万科、阿里)。如果相同的列名不止一个,可以通过on参数指定按照哪一列进行合并,代码如下。

df3 = pd.merge(df1, df2, on='公司')

默认的合并其实是取交集(inner连接),即选取两个表共有的内容。如果想取并集(outer连接),即选取两个表所有的内容,可以设置how参数,代码如下。

df3 = pd.merge(df1, df2, how='outer')

公司	分数	股价
0	万科	90.0	20.0
1	京东	NaN	30.0
2	百度	85.0	NaN
3	阿里	95.0	180.0

运行后df3的内容见下表,可看到所有数据都在,原来没有的内容则为空值(NaN)。

如果想保留左表(df1)的全部内容,而对右表(df2)不太在意,可以将how参数设置为left,代码如下。

 df3 = pd.merge(df1, df2, how='left')

 公司	分数	股价
0	万科	90.0	20.0
1	阿里	95.0	180.0
2	百度	85.0	NaN

如果想保留右表(df2)的全部内容,而不太在意左表(df1),可以将how参数设置为right。

如果想根据行索引进行合并,可以设置left_index和right_index参数,代码如下。

df3 = pd.merge(df1, df2, left_index=True, right_index=True)

公司_x	分数	公司_y	股价
0	万科	90.0	万科	20.0
1	阿里	95.0	阿里	180.0
2	百度	85.0	京东	30.0

将两个表按照它们的行索引进行了合并。

补充知识点:根据行索引合并的join()函数join()函数也是一种数据表拼接的常用函数,它可以根据行索引进行数据表合并,演示代码如下。

df3 = df1.join(df2, lsuffix='_x', rsuffix='_y')

	公司_x	分数	公司_y	股价
0	万科	90.0	万科	20.0
1	阿里	95.0	阿里	180.0
2	百度	85.0	京东	30.0

需要注意的是,使用join()函数进行数据表拼接时,若两个表中存在同名列,则需要设置lsuffix参数(左表同名列的后缀,suffix是“后缀”的意思,l表示left)和rsuffix参数(右表同名列的后缀,r表示right);若没有同名列,则可以直接写成df1.join(df2),这种写法与使用merge()函数相比更为简洁。

该知识点在进行数据表合并时会有应用。

2.concat()函数

concat()函数是一种全连接(UNION ALL)方式,它不需要对齐,而是直接进行合并,即不需要两个表的某些列或索引相同,只是把数据整合到一起。因此,该函数没有how和on参数,而是通过axis参数指定连接的轴向,该参数默认为0,按行方向连接,即纵向拼接。

df3 = pd.concat([df1, df2], axis=0)

	公司	分数	股价
0	万科	90.0	NaN
1	阿里	95.0	NaN
2	百度	85.0	NaN
0	万科	NaN	20.0
1	阿里	NaN	180.0
2	京东	NaN	30.0

df3的行索引为原来两个表各自的索引,若要重置索引,可以在concat()函数中设置ignore_index=True,忽略原有索引,生成新的数字序列作为索引。

若要按列方向连接,即横向拼接,可以设置axis参数为1,代码如下。

df3 = pd.concat([df1, df2], axis=1)
3.append()函数

append()函数可以看成concat()函数的简化版,效果和pd.concat([df1,df2])类似,代码如下。

df3 = df1.append(df2)

append()函数还有个常用的功能,和“列表.append()”一样,可用来新增元素,代码如下。

df3 = df1.append({'公司': '腾讯', '分数': '90.0'}, ignore_index=True)

这里一定要设置ignore_index=True以忽略原索引,否则会报错,此时df3的内容见下表。

数据表拼接的相关知识点在进行电影数据拼接时会有应用。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐