Pandas: Python界的Excel

夏侯华彩
2023-12-01

Pandas: Python界的Excel

前言

在日常工作中使用Excel可以非常方便地进行数据分析,但是在数据量变大时(超过10000行)时Excel会变得很慢,并且Excel分析出来的数据难以给其它程序(比如用于机器学习的模型训练)使用。

本文以Excel的角度来对照Pandas的相应功能,以帮助快速掌握Pandas进行数据分析。

Excel vs. Pandas

在Jupyter Notebook中引入Pandas库:

import pandas as pd
from pandas import DataFrame, Series

基本概念

导入数据

# 默认UTF-8编码
df = pd.read_csv('./data.txt')

# 打开中文乱码时,可尝试通过指定编码来解决
df = pd.read_csv('./汽车销量.csv', encoding='GB18030')

样例数据:汽车销量.csv

当数据中含有长编码时,Pandas会将该字段作为数值来处理,如果数据中含有空数据的行,Pandas会将该字段作为float64,从而导致长编码后面加上.0
解决该问题的方法是导入数据时,指定列的数据类型:

# 将code列设置为字符串(np.object_),将num列设置为浮点数(np.float64)
df = pd.read_csv('./data.txt', 
				dtype={'code1':pd.np.object_, 'code2':pd.np.object_, 'code3':pd.np.object_, 'num1':pd.np.float64, 'num2':pd.np.float64 })

导入数据后,执行df.info()检查列的格式是否正确。

在导入数据时也可以通过usecols参数指定只导入特定的列:

df = pd.read_csv('./data.txt', usecols = ['code1', 'code3'])

重命名列:

df = df.rename(columns={'code1': '代码1', 'num1': '数值1'}, errors='raise')

设置索引列:

df = df.set_index('车型', drop=False)

如果不指定索引列,默认索引列为一个从0开始递增的自然数数列。

导出数据

# 默认使用UTF-8编码
df.to_csv('./out.csv', index=None)

# 指定GB18030编码
df.to_csv('./out.csv', index=None, encoding='GB18030')

# 遇到小数导出后精度问题,可以通过指定保留的小数位数来解决,比如保留5位小数
df.to_csv('./out.csv', index=None, float_format='%.5f')

表格

Excel中的”表格“对应Pandas库的DataFrame:

查看表格头10条记录:

df.head(10)

查看表格尾10条记录:

df.tail(10)

查看表格10条抽样记录:

df.sample(10)

查看表格缩略数据:

df

查看表格统计数据:

df.describe()

查看表格的行数和列数:

df.shape
# 行数
df.shape[0]
# 列数
df.shape[1]

Excel中的”行“对应Pandas的DataFrame的一个切片(Slice):

df[row_index_slice | bool_array]
# 或根据索引列的行标签选取
df.loc[row_label | row_label_array | row_label_slice]
# 或根据索引列的行号选取,行号从0开始
df.iloc[row_index | row_index_array | row_index_slice]

注意:Pandas的行号从0开始。

根据行标签选取行:

“车型”为“丰田卡罗拉”的行:

df[df['车型'] == '丰田卡罗拉']
# 或
df.loc['丰田卡罗拉']

"车型“为”大众朗逸“和”大众速腾“的行:

df[df['车型'].isin(['大众朗逸','大众速腾'])]
# 或
df.loc[['大众朗逸','大众速腾']]

根据行号选取行:

第1行:

df[:1]
# 或
df.iloc[0]

前3行:

df[:3]
# 或
df.iloc[:3]

第5行到第10行:

df[4:10]
# 或
df.iloc[4:10]

第8行:

df[7:8]
# 或
df.iloc[7]

后3行:

df[-3:]
# 或
df.iloc[-3:]

Excel中的”列“对应Pandas的Series:

df[column_label | column_label_array]
# 或根据列名选取列
df.loc[: , column_label | column_label_array | column_label_slice]
# 或根据列号选取列
df.iloc[: , column_index | column_index_array | column_index_slice]

根据列名选取列:

”车型“一列:

df['车型']
# 或
df.车型
# 或
df.loc[:, '车型']

”车型“和”销量“两列:

df[['车型','销量']]
# 或
df.loc[: , ['车型','销量']]

从”车型“到”销量“的所有列:

df.loc[: , '车型':'销量']

根据列号选取列

第1列:

df.iloc[:, :1]

从第2到第3列:

df.iloc[:, 1:3]

最后1列:

df.iloc[:, -1:]

单元格

Excel中的”单元格“对应Pandas的DataFrame的一个切片(Slice):

# 根据行标签和列名选取一个或多个单元格
df.loc[row_label | row_label_array | row_label_slice, column_label | column_label_array | column_label_slice ]

# 根据行号和列号选取一个或多个单元格
df.iloc[row_index | row_index_array | row_index_slice, column_index | column_index_array | column_index_slice ]

根据行标签和列名选取一个或多个单元格:

"吉利博瑞"的”销量“:

df.loc['吉利博瑞','销量']

"吉利博瑞"的"厂商"和”销量“:

df.loc['吉利博瑞',['厂商','销量']]

"大众迈腾"和"大众捷达"的"厂商"和”销量“:

df.loc[['大众迈腾','大众捷达'],['厂商','销量']]

"吉利博瑞"的从"厂商"到”销量“列:

df.loc['吉利博瑞','厂商':'销量']

根据行号和列号选取一个或多个单元格:

第1行第2列:

df.iloc[0,1]

第5行到第10行的第2列到第3列:

df.iloc[4:10, 1:3]

基本操作

插入行

复制“DS 5”行,插入到最后:

df2 = df.append(df.loc['DS 5'])

插入列

复制”销量“列,插入到最后,新列名为”备注“:

df['备注'] = df['销量']

在最前面新增一列”排名“,从1开始自动填充该列:

df.insert(0, "排名", range(1, len(df) + 1))

删除行

删除”DS 5"行:

df.drop('DS 5', axis=0)

删除列

删除”备注“列:

df.drop(columns='备注')
# 或
df.drop('备注', axis=1)

数据操作

筛选

厂商为“东风日产”的记录:

df[df['厂商'] == '东风日产']

厂商为“东风日产”的总销量:

df[df['厂商'] == '东风日产']['销量'].sum()

厂商为“东风日产”的平均销量:

df[df['厂商'] == '东风日产']['销量'].mean()

厂商为“东风日产”的计数:

df[df['厂商'] == '东风日产']['销量'].count()

厂商为“东风日产”的最大销量:

df[df['厂商'] == '东风日产']['销量'].max()

厂商为“东风日产”的最小销量:

df[df['厂商'] == '东风日产']['销量'].min()

多选:厂商为“一汽大众”和“一汽丰田”的记录:

df[df['厂商'].isin(['一汽大众', '一汽丰田'])]

反选:厂商不为“上汽通用”的记录:

df[df['厂商'] != '东风日产']

反选:厂商不为“一汽大众”和“一汽丰田”的记录:

# Python使用波浪号~表示“非”操作
df[~df['厂商'].isin(['一汽大众', '一汽丰田'])]

# 或
df[df['厂商'].isin(['一汽大众', '一汽丰田']) == False]

排序

升序排序:

df.sort_values('销量', ascending=True, inplace=True)

降序排序:

df.sort_values('销量', ascending=False, inplace=True)

唯一值

”厂商“列的唯一值:

# unique array
df['厂商'].unique()

# size of unique array
len(df['厂商'].unique())

删除重复值

先故意插入两个重复行:

df2 = df.append(df.iloc[-2:])

重复记录数:

df2.duplicated().sum()

显示重复记录:

df2[df2.duplicated()]

删除重复记录:

df2.drop_duplicates(inplace=True)

空值处理

空字符串:

先故意将“DS 5"和"一汽骏派A70E"的厂商设为空字符串''

df2.loc['DS 5', '厂商'] = ''
df2.loc['一汽骏派A70E', '厂商'] = ''

空字符串记录数:

(df2['厂商'].astype(bool) == False).sum()

查找空字符串记录:

df2[df2['厂商'].astype(bool) == False]

空值:

替换空字符串为NaN:

df2['厂商'].replace('', pd.np.nan, inplace=True)

替换后NaN记录数:

df2['厂商'].isna().sum()

查找NaN记录数:

df2[df2['厂商'].isna()]

删除NaN记录:

df2.dropna(subset=['厂商'], inplace=True)

替换NaN记录:

df2['厂商'].fillna(value='Unknown', inplace=True)

转换数据类型

查看各列的数据类型:

df.dtypes

转换成数值:

s = pd.Series(['apple', '1.0', '2', -3])

# 忽略不是数值的值
s2 = pd.to_numeric(s, errors='ignore')

# 将不是数值的值替换成NaN
s2 = pd.to_numeric(s, errors='coerce')

# 转换时作类型转换(降低精度)
s2 = pd.to_numeric(s, errors='coerce', downcast='float')

转换成日期:

s = pd.Series(['3/11/2000', '3/12/2000', '3/13/2000'])

# 将不是日期的值替换成NaT
s2 = pd.to_datetime(s, errors='coerce')

转换成字符串:

s3 = s2.astype(str)

函数

新增”销量过万车型“列,对销量过万的车型该列值为Y:

def sales_flag(value):
    if value >= 10000:
        return 'Y'
    else:
        return 'N'

df2['销量过万车型'] = df2['销量'].apply(sales_flag)

查看销量过万车型:

df2[df2['销量过万车型'] == 'Y']

数据透视表(分类统计)

分类求和

按”厂商“统计销量:

df.groupby('厂商')['销量'].sum()
# 或
df.pivot_table(index='厂商', values='销量', aggfunc='sum')

分类计数

按”厂商“统计记录数:

df['厂商'].value_counts()
# 或
df.groupby('厂商')['销量'].count()

分类平均值

按”厂商“统计平均销量:

df.groupby('厂商')['销量'].mean()

分类最大值

按”厂商“统计最高销量:

df.groupby('厂商')['销量'].max()

分类最小值

按”厂商“统计最低销量:

df.groupby('厂商')['销量'].min()

TODO: 更多的分类统计场景

Pandas教程

参考文档

 类似资料: