Pandas基础笔记

Pandas基础笔记

Pandas是数据分析中最受欢迎的Python Package之一,它的官方文档为Pandas Documentation。Pandas主要用于表格数据(行列格式)的数据操作,同时它提供从多种数据源读取数据的能力,以及丰富的数据操作功能,包括数据聚合、数据分析和数据清洗等。Pandas也可以与其他数据科学相关的Package进行良好的配合,包括numpy、scikit-learn、matplotlib、seaborn、plotly等。

可以通过pip或者conda来进行pandas的安装,使用install命令即可。

1
2
pip install pandas
conda install pandas

我们在代码中通常以pd的形式引入Pandas package,后面也都遵循这种约定。

1
import pandas as pd

数据读取

Pandas主要面对的是有行列的表结构,并且使用DataFrame Class来进行表征,表的每一列又对应一个Class,为Series。因此学习Pandas的核心就在于学习DataFrame以及Series的操作。(主要是DataFrame)

DataFrame包含行和列,每一列有自己的列名,每一行也会有一个index,这个index可以由系统自动生成,此时index为从0自增的自然数,也可以由用户指定某一列为index。

Pandas中的index:在Pandas中,index主要可以提供如下功能

  • 更方便的数据查询
  • 使用index可以获得性能提升
    • 如果index是唯一的,pandas会使用哈希表优化,查询性能为O(1)
    • 如果index不是唯一的,但是有序,Pandas会使用二分查找算法,查询性能为O(logN)
    • 如果index是完全随机的,那么每次查询都要扫描全表,查询性能为O(N)
  • 自动的数据对齐功能
    • 如果将两个Series进行操作,index相同的可以进行相互操作,不相同则为空(NaN,None之类的)
  • 更多更强大的数据结构支持
    • CategoricalIndex:基于分类数据的index,提升性能
    • MultiIndex:多维索引,用于groupby多维聚合后结果等
    • DatetimeIndex:时间类型索引,强大的日期和时间的方法支持

Pandas支持从多种格式的数据进行读取,并生成表结构,常用的数据来源有csv、txt、excel、json、mysql数据库等,它们分别可以用不同的api来进行读取:

数据类型 说明 读取方法
csv、tsv、txt 用逗号或tab分隔的纯文本文件 pd.read_csv
excel xls或者xlsx文件(支持sheet的选择) pd.read_excel
json json文件,每一列数据按照index:value分开存储 pd.read_json
mysql 关系型数据库表 pd.read_sql

其中最为常用的是pd.read_csv,它支持下面一些常用的参数:

  • filepath_or_buffer:支持csv、tsv、txt等文件路径,这个文件路径也可以是一个URL链接,链接对应内容为以指定字符分隔的文本

  • header:指定以哪一行作为header,为None表示没有header。默认使用第1行

  • index_col:指定以哪一列作为index列,默认为自增index。可以传入数字(从0开始),也可以传入列名

  • sep='\t',:指定分隔符

  • names:接受一个字符串数组,用于自定义列名

  • usecols:接受一个字符串数组,表示仅读取指定列到内存当中

如果要读取数据库中的表,那么需要先建立连接,在read方法中提供连接参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pymysql
import pandas as pd

conn = pymysql.connect(
host='xxx.x.x.x',
user='xxx',
passward='xxx',
database='xxx',
charset='xxx') # 数据库配置

mysql_page = pd.read_sql(
"select * from xxx表名", # 这是SQL语句
con = conn
)

除了从文件中读取数据,我们还可以从列表或者字典中创建Series或者DataFrame。

对于Series来说,我们可以从列表或者字典中创建Series对象。如果传入的是列表,那么index就是默认的自增index;如果传入的是字典dict,那么其中的key就变为index。

1
2
3
4
5
6
7
8
9
10
11
# 从list中创建, 通过name指定列名
li = [1,2,3,4,5]
series = pd.Series(li, name='col')

# 从dict中创建
dict = {'index0':1, 'index1':2, 'index2':3, 'index3':4}
series = pd.Series(dict, name='col')

# 查询Series
series[0] # 返回原生数据类型
series[[0,1,2]] # 返回Series

对于DataFrame来说,我们可以从字典中创建Series对象,其中每一个Key对象是一个列表,此时字典的每个Key表示一列,列表中的每个value就是对应一行的值。

1
2
3
4
5
6
# 从dict中创建,通过index=[...]指定index
dict = {
'col1': [1, 2, 3, 4, 5],
'col2': [5, 4, 3, 2, 1]
}
df = pd.DataFrame(dict, index=[1,2,3,4,5])

数据保存

Pandas同样允许将DataFrame对象输出成各种格式的文件,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
# output to csv
df.to_csv("test_out.csv", index=False)

# output to json
df.to_json("test_out.json")

# output to text, 需要手动指定分隔符
df.to_csv('test_out.txt', header=df.columns, index=False, sep=' ')

# output to excel
df.to_excel("test_out.xlsx", index=False)

基础数据操作

信息查询

在通过read方法得到了DataFrame对象之后,可以通过一些简单的方法来初步查看该数据的信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
df.head()  # 查看前5行

df.tail(n=10) # 查看后10行

df.shape # 查看行列数目,几行几列,先行后列。注意index列不计算在shape中

df.index # 显示index名

df.columns # 显示列名

df.info() # 显示概述,包括每列的名词、非空值、类型以及占用空间等

df.describe() # 显示所有数字列的统计摘要,包括平均值、最大最小值、标准差、分位数等
df.describe().T # df.describe()得到的结果也是一个DataFrame,可以使用T来查看转置效果

行列查询

在DataFarme中,对行列查询是基本操作。

下面是查询行的操作:

1
2
3
4
5
6
7
8
# 查询行需要通过index来完成
df.loc[index] # 返回一行,index是对应索引值

df.loc[[index1,index2, ...]] # 返回多行

df.loc[index1:index3] # 使用切片,此方式包含末尾元素

df.iloc[] # 传入的是数字位置(第几个)其余用法与.loc相同

下面是查询列的操作:

1
2
3
4
5
# 查询列需要通过列名来完成
df[column] # 返回一列,column是对应列名
df.column # 直接用.来调用

df[[column1, column2, ...]] # 返回多列,中间列表是多列对应的名称

下面是行列同时查询的操作:

1
2
3
4
5
6
# .loc可以同时指定行和列,通过逗号隔开,前面是行范围,后面是列范围
# 行列范围的指定和上面单独指定行列是相同的,包括单个label值,列表,切片等
df.loc[index, column]
df.loc[index, [column1, column2, ...]]
df.loc[[index1, index2, ...], column]
df.loc[[index1, index2, ...], [column1, column2, ...]]

并且在查询的时候,我们可以结合判断条件来尽心过滤和筛选。实际上条件表达式会返回一个由布尔值组成的Serise,长度正好是整个DataFrame的长度。在返回结果的时候,类似于传递了一个Mark,只有当Series对应位置上是True的时候,该行才会返回。

1
2
3
4
5
6
7
8
9
10
11
12
# 条件表达式的使用:df[条件表达式]
# 单条件查询
df[df['age'] >= 18]

# 多条件查询,每个条件都使用()&()进行连接
df[(df['age'] >= 18) & (df['unit'] == 'catchu')]

# 由于条件表达式是对行的选取规则,因此也可以用在.loc中
df.loc[df['age']==18]

# 字符串列的使用方式
df[df['name'].str.startswith('k')]

这里需要注意的是,如果某一列Series中存放的是字符串类型的数据,我们是无法直接调用字符串某个确切的字符串对应的方法的,而是需要先获取Series的str属性,然后在属性上调用函数。Series.str不是python的原生字符串,而是自己的一套方法,不过大部分和原生str很相似,可以参考Series String hadnling|pandas

新增或修改数据列

在Pandas中可以使用直接修改,df.apply等方式来新增或修改数据。

直接修改指的是利用.loc方法进行定位,然后直接指定对应的value:

1
2
3
4
5
6
7
8
df.loc[index, column] = xxx # 修改某行某列的值 xxx = one value

df.loc[:, column] = xxx # 修改某列的值 xxx = one series

df.loc[index, :] = xxx # 修改某行的值 xxx = one series

# 同样可以用来新增数据
df.loc[:, new_column] = xxx # 新增一列 xxx = one series

df.apply方法的返回值是一个Series,它的含义是沿着DataFrame的某一个轴执行函数,相当于每次传入了一个Series,然后得到一个value。最终所有的value组成一个Serise。

  • axis=0:沿着横轴方向,每次传入一列给函数,最终得到的Series是横向的
  • axis=1:沿着竖轴方向,每次转入一行给函数,最终得到的Series是竖向的

可以理解为axis表示最终得到的结果与哪个轴相同,axis=0表示最终得到的Series与x轴相同,即得到的Series是横向的。

这样理解的话,axis=0表示水平轴,axis=1表示垂直轴,与numpy中有所区别,建议实际使用过程中直接尝试不同的axis查看对应的效果,毕竟只有两个选项。

利用apply方法可以新增一列或者一行:

1
2
3
4
5
# 新增一行
df.loc[0, :] = df.apply(lambda x: len(x), axis=0)

# 新增一列
df.loc[:, 'age+1'] = df.apply(lambda x: x['age'] + 1, axis=1)

列名/index处理

列名处理指的是我们可以修改DataFrame的列名,一共有两种方式:

1
2
3
4
5
# 直接通过修改属性来修改列名,此方式需要给出所有的列名
df.column = [xxx,xxx,xxx,...]

# 通过提供dict来修改列名,指定旧列名以及目标新列名
df.rename(columns = {old_col: new_col}, inplace=True)

index处理指的是我们可以修改DataFrame的Index:

1
2
3
4
5
6
7
8
# 重新设定index
df.set_index('指定列',inplace=False, drop=False)

# - inplace:表示是否要替换原有索引(对应单索引和复合索引)
# - drop:表示是否要丢弃这一列索引数据,如果为False表示将索引仍然保留作为表格内容

# 还原索引,重新变为默认的整型索引
df.reset_index()

缺失值处理

在处理缺失值之前,首先需要检测缺失值。Pandas提供了isnull()notnull()等方法来判断空值:

1
2
3
4
5
# 以下方法均返回一个DataFrame,其中每个单元格的Value是一个布尔值,代表当前单元格是否为空。注意isnull和isna,notnull和notna完全相同。
df.isnull()
df.isna()
df.notnull()
df.notna()

一种处理缺失值的方式是直接丢弃缺失值,Pandas中提供dropna方法来删除缺失值。

1
df.dropna(axis=0|1, how=any|all, inplace=True|False, subset=[xxx])
  • axis:删除行还是列,可选值为0或1
    • 等于0或者index表示按行删除,默认为0
    • 等于1或者columns表示按列删除
  • how:可选值为any或all
    • any:出现空值就删除
    • all:所有都是空值才删除
  • inplace:布尔值,是否修改当前df
    • True:修改当前df
    • False:返回新的df
  • subset:表示接受空值判断的子集columns

另外一种处理缺失值的方式是进行填充,Pandas中提供fillna方法来填充缺失值。

1
df.fillna(value=xxx, method=xxx, axis=0|1, inplace=True|False)
  • value:用于填充的值,可以是单个值,或者字典(key是列名,value是值),如果是填充字典的情况,则表示检测key那一列,如果是空,就替换为value。这样使得我们能够对不同列采取不同的填充措施。
  • method:填充方法,可选值为backfill、ffill、bfill
    • ffill:使用前一个不为空的值进行填充
    • backfill/bfill:使用后一个不为空的值进行填充
  • axis:按行填充还是列填充,同dropna
  • inplace:是否修改当前df,同dropna

重复值处理

Pandas中提供drop_duplicates方法来进行去重,此方法可以接收列名,表示按照哪一列或者哪几列进行去重。

1
2
3
df.drop_duplicates()  # 按照所有列去重
df.drop_duplicates('name') # 按照name列去重
df.drop_duplicates(['name', 'age']) # 按照name和age列去重

数据排序

Pandas同样支持数据的排序。

1
2
3
4
5
6
7
8
9
10
# 对于Series来说,排序方法为
Series.sort_values(ascending=True, inplace=False)
# - ascending:默认为True升序排序,为False降序排序
# - inplace:是否修改原始Series

# 对于DataFrame来说,排序方法为
DataFrame.sort_values(by,ascending=True,inplace=False)
# - by:排序的基准,可以提供单个列名或者列名数组
# - ascending:bool或者List,升序还是降序,如果是List则对应by的多列
# - inplace:是否修改原始DataFrame

数据统计

常见的数据统计方法有:

1
2
3
4
5
6
7
8
9
10
.mean()  # 平均值
.max() # 最大值
.min() # 最小值
.sum() # 求和
.unique() # 可以查看一列中有哪些值
.nunique() # 返回某一列的不重复值的个数
.value_counts() # 可以查看有哪些值并进行计数
df.cov() # 协方差矩阵
df.corr() # 相关系数矩阵
df['xxx'].corr(df['yyy']) # 单独查看两列的相关系数

高级数据操作

Merge

Pandas中的Merge,相当于Sql中的join,方法签名如下:

1
pd.merge(left,right,on=None,left_on=None,right_on=None,left_index=False,right_index=False,suffixes=('_x','_y'),copy=True,indicator=False,validate=None)
  • left,right:需要进行join的左表和右表
  • how:join类型,有left、right、outer、inner,与sql中的连接定义一致
  • on:进行join的key,left和right都需要有这个key
  • left_on:left的df或series的key
  • right_on:right的df或series的key
  • left_index,right_index:使用index而不是普通的column做join
  • suffixes:两个元素的后缀,如果列有重名,自动添加后缀

Concat

Pandas中的concat用于合并相同格式的数据,可以完成上下拼接或者左右拼接,给DataFrame添加行或者列。合并时按照索引或者列名进行对齐,方法签名如下:

1
pd.concat(objs,axis=0,join='outer',ignore_index=False)
  • objs:接收一个列表,其中的元素可以是DataFrame,Series或两者混合
  • axis:默认0代表按行合并,1表示按列合并
  • join:合并的时候索引的对齐方式,默认为outer ,也可以是inner
  • ignore_index:是否忽略掉原来的数据索引

GroupBy

Pandas中的groupby方法可以做到先对数据进行分组,然后在每个分组上应用聚合函数或者转换函数

1
2
3
4
5
6
7
8
9
10
groupby('columns')  # 原来的columns变成索引,以此看其他列

groupby(['columns1','colunms2',...]) # 形成多级索引(分层索引)
# as_index=False:指定不要形成多级索引

# 如果需要同时查看多种数据统计,可以使用.agg方法
# import numpy as np
df.groupby('unit').agg([np.sum, np.count_nonzero])
# 也可以传dict作为参数,指定对特定列执行特定的操作
df.groupby('unit').agg({'age':np.mean,'name':np.count_nonzero})

Pandas加速

pandarallel

在pandas中运行例如apply方法的时候,如果数据量过大,处理时需要耗费很多时间。默认pandas使用单核进行运行,而pandarallel提供了一种并行处理的方式,利用多核并行来加速pandas的处理。这里简单介绍使用方法:

1
2
3
4
5
6
from pandarallel import pandarallel

pandarallel.initialize(progress_bar=True)

# 之后可以在DataFrame上调用parallel_apply方法
result = df.parallel_apply(some_func)

参考文章

  1. pandas tutorial|datacamp
  2. OSError: [Errno 28] No space left on device · Issue #127 · nalepae/pandarallel

Pandas基础笔记
http://example.com/2023/08/07/Pandas基础笔记/
作者
EverNorif
发布于
2023年8月7日
许可协议