项目概况

数据分析与清洗

2026-01-2916 min read数据处理
pandas

Pandas

作者: 西魏陶渊明 博客: https://blog.springlearn.cn/

天下代码一大抄, 抄来抄去有提高, 看你会抄不会抄!

本系列文章还是引用之前的理念,阅读文章,你不需要记,只要知道这一篇在讲什么即可,收藏起来,用的时候过来抄代码。

前面第一篇文章算是入门, 蜻蜓点水比较简单,而这一篇是干货满满, 并配有数据案例。一定要看完, 因为这将是后面我们具体案例分析的基础。

这一篇文章中,我们将深入研究如何使用Pandas进行数据探索和清洗。您将学习如何处理缺失值、重复数据、异常值等常见的数据质量问题。通过使用Pandas的强大功能,如数据筛选、排序和重塑,您将能够有效地准备和整理数据,为后续的分析工作打下坚实的基础。

系列文章:

  • 第一篇:Pandas入门指南:掌握Python数据处理利器
  • 第二篇:数据探索与清洗:使用Pandas轻松预处理数据 【当前篇】
  • 第三篇:深入了解Pandas数据结构:Series与DataFrame
  • 第四篇:数据选择与过滤:Pandas中的强大索引技巧
  • 第五篇:数据操作与转换:学会利用Pandas处理复杂任务

一、重点内容

1.1 数据查看

  • 数据预览:使用head()函数预览数据的前几行,以了解数据的整体结构和格式。
  • 基本统计量:使用describe()函数获取数据的基本统计信息,如均值、标准差、最小值、最大值等,帮助了解数据的分布和范围。
  • 唯一值与计数:使用unique()和value_counts()函数获取列中的唯一值和各个值的计数,以了解数据的分类和频率分布。
  • 缺失值检测:使用isnull()函数检测数据中的缺失值,并通过sum()函数统计每列的缺失值数量,帮助了解数据的完整性。

1.2 数据清洗

  • 处理缺失值:使用dropna()函数删除包含缺失值的行或列,或者使用fillna()函数填充缺失值,选择适当的方法取决于具体的数据情况。
  • 处理重复值:使用duplicated()函数检测重复值,并使用drop_duplicates()函数删除重复值,确保数据的唯一性。
  • 异常值处理:通过使用可视化工具和基本统计分析来识别和处理异常值,可以使用过滤、替换或删除等方法来应对异常值。
  • 数据类型转换:使用astype()函数将列的数据类型转换为正确的类型,确保数据的一致性和准确性。
  • 数据格式化与规范化:对于字符串类型的数据,可以使用字符串处理函数(如str.lower()、str.upper()、str.strip()等)对数据进行格式化和规范化。

1.3 数据预处理

  • 特征选择与删除:根据分析目标和特征的相关性,选择相关特征并删除不相关或冗余的特征,以提高后续分析的效果。
  • 数据转换与衍生:使用apply()函数或自定义函数对数据进行转换和衍生,如特征缩放、数值转换、日期提取等,以适应不同的分析需求。
  • 数据合并与拆分:通过使用merge()函数或concat()函数,可以将多个数据集合并成一个,或者将一个数据集拆分成多个,以满足数据分析的需要。
  • 数据重塑与透视:使用pivot()函数或melt()函数,可以对数据进行重塑和透视,以更好地理解和分析数据的关系和趋势。

二、数据查看

当我们在接触到一份二维表格数据, 我们会先用Excel来查看数据的大概类型, 只有清楚了表格的内容信息,才知道如何来处理 这份数据。为了让大家快速的学习,我这里也列一个表格数据。然后我们针对这个数据进行分析。

在这里插入图片描述 首先我们读取数据。

python
1import pandas as pd 2import numpy as np 3 4df = pd.read_excel('./销售金额.xlsx')

2.1 数据预览

这个表格有多少行,多少列,每一列的类型是什么?

2.1.1 查看行数列数

python
1# 12 2 2# 12行2列 3print(df.shape)

2.1.2 查看头尾数据

python
1# 日期 销售金额 2# 0 2023-01 100.0 3print(df.head(1)) 4 5# 日期 销售金额 6# 11 2023-12 534.0 7print(df.tail(1))

2.1.3 随机抽查

  • axios = 0 查看行数
  • axios = 1 查看列数
python
1# 随机查看2行 2# 日期 销售金额 3# 11 2023-12 534.0 4# 1 2023-02 80.0 5print(df.sample(2, axis=0))

2.1.4 查看数据类型

查看每一列的数据类型,也可以查看指定列的类型。

python
1# 日期 object 2# 销售金额 float64 3# dtype: object 4print(df.dtypes) 5 6# float64 7print(df['销售金额'].dtypes)

2.1.4 查看所有信息

前面如果感觉麻烦,我们可以直接使用info方法。 info()函数提供了更详细的数据信息,包括每列的名称、非空值数量和数据类型。 它还可以显示数据集的内存占用情况和总体摘要。

从下面内容看,日期列都有值。no-null = 12 说明都有值,而销售金额 no-null = 11 说明有一列没有值。 memory usage: 320.0+ bytes 是占用的内存大小,可以看到只有320+ 字节。

python
1# <class 'pandas.core.frame.DataFrame'> 2# RangeIndex: 12 entries, 0 to 11 3# Data columns (total 2 columns): 4# # Column Non-Null Count Dtype 5# --- ------ -------------- ----- 6# 0 日期 12 non-null object 7# 1 销售金额 11 non-null float64 8# dtypes: float64(1), object(1) 9# memory usage: 320.0+ bytes 10# None 11print(df.info())

2.2 基本统计量

2.2.1 统计量函数

使用describe()函数获取数据的基本统计信息,如均值、标准差、最小值、最大值等,帮助了解数据的分布和范围。

text
1# count 11.000000 非缺失值有11个 2# mean 106.090909 平均值 3# std 145.143002 标准差 4# min 22.000000 最小金额 5# 25% 47.500000 统计学中的四分位数 6# 50% 60.000000 统计学中的四分位数 7# 75% 90.000000 统计学中的四分位数 8# max 534.000000 最大金额 9print(df['销售金额'].describe())

这里面比较难理解的就是四分位数,这个四分位数主要是让我们了解数据的分布和范围。

在这里插入图片描述

举例

我们将销售金额从小到大排序,分别找25% 50% 75%位置的值。

[ 22. 23. 45. 50. 55. 60. 75. 80. 100. 123. 534.]

  • 25% 47.5
  • 50% 60 (因为正好11个值,所以中间就是第六个值,所以是60)
  • 75% 90

2.2.2 其他统计量函数

效果等同于前面 describe 的效果。

序号函数说明
1mean()计算每列数据的平均值。
2median()计算每列数据的中位数。
3sum()计算每列数据的总和。
4min()计算每列数据的最小值。
5max()计算每列数据的最大值。
6std()计算每列数据的标准差。
7var()计算每列数据的方差。
8count()计算每列数据的非缺失值数量。
9quantile()计算每列数据的指定分位数。
10corr()计算每列数据之间的相关系数。
python
1print(df['销售金额'].count()) 2print(df['销售金额'].mean()) 3print(df['销售金额'].std()) 4print(df['销售金额'].min()) 5print(df['销售金额'].max()) 6print(df['销售金额'].quantile(0.25)) 7print(df['销售金额'].quantile(0.5)) 8print(df['销售金额'].quantile(0.75)) 9print(df['销售金额'].corr(df['销售金额'], method='spearman'))

这里面比较难得是 corr 函数,这个统计函数。用于反应两组数据是否具有正相关性。 下面举一个生活中的例子。

text
1月份 销量(单位) 广告费用(美元) 21 100 500 32 120 600 43 110 550 54 130 700 65 140 800 76 150 900

使用斯皮尔曼相关系数,您可以计算销售量和广告费用之间的关系强度。假设您计算出的斯皮尔曼相关系数为0.85。这意味着销售量和广告费用之间存在着较强的正相关关系。

2.2.4 相关性分析

  • spearman 斯皮尔曼相关系数(Spearman correlation coefficient)
  • kendall 肯德尔相关系数(Kendall correlation coefficient)
python
1 2data = { 3 '月份': [1, 2, 3, 4, 5, 6], 4 '销量金额': [100, 120, 110, 130, 140, 150], 5 '广告费用': [500, 600, 550, 700, 800, 900] 6} 7 8df = pd.DataFrame(data) 9 10# 0.9999999999999999 说明广告费用越高,销售金额越高 11print(df['广告费用'].corr(df['销量金额'],method='kendall')) 12 13 14data2 = { 15 '月份': [1, 2, 3, 4, 5, 6], 16 '销量金额': [100, 90, 80, 70, 60, 50], 17 '广告费用': [500, 600, 550, 700, 800, 900] 18} 19 20df = pd.DataFrame(data2) 21 22# -0.9538209664765318 说明广告费用越高,销售金额越低 23# 默认 spearman 24print(df['广告费用'].corr(df['销量金额']))

2.3 唯一值与计数

为了方便我们演示,我们换一个表格数据。

在这里插入图片描述

2.3.1 唯一值

统计参数统计的角色

python
1# ['刘备' '关羽' '张飞' '赵云' '黄忠' '马超' '曹操' '孙权' '周瑜'] 2print(df['角色'].unique())

2.3.2 统计颜色出现的次数

  • 可选参数
参数说明
normalize如果设置为True,则返回的计数将以相对频率的形式显示,而不是绝对计数。默认值为False。
sort如果设置为True,则按计数值的降序对结果进行排序。默认值为True。
ascending如果设置为True,则按计数值的升序对结果进行排序。默认值为False。
bins用于连续型数据的分箱数。可以传递一个整数值,将数据分成指定数量的等宽区间。
dropna如果设置为False,则不会忽略缺失值(NaN)并将其视为一个独立的类别。默认值为True,即忽略缺失值。
python
1# 统计颜色出现的次数 2# 红色 4 3# 绿色 2 4# 蓝色 2 5# 黄色 1 6print(df['颜色'].value_counts()) 7 8# 升序 9# 颜色 10# 黄色 1 11# 绿色 2 12# 蓝色 2 13# 红色 4 14# Name: count, dtype: int64 15print(df['颜色'].value_counts(ascending=True)) 16 17# 黄色 0.111111 18# 绿色 0.222222 19# 蓝色 0.222222 20# 红色 0.444444 21# Name: proportion, dtype: float64 22print(df['颜色'].value_counts(ascending=True,normalize=True))

2.4 缺失值检测

这个问题可能是我们遇到最多的情况情况了。 在这里插入图片描述 看下面这个表,我们用pandas读取数据后发现, 销售金额中既有缺省值,也有空字符。

python
1# 日期 销售金额 2# 0 2023-01 100 3# 1 2023-02 80 4# 2 2023-03 50 5# 3 2023-04 60 6# 4 2023-05 NaN 7# 5 2023-06 23 8# 6 2023-07 45 9# 7 2023-08 55 10# 8 2023-09 11# 9 2023-10 75 12# 10 2023-11 123 13# 11 2023-12 534 14print(df.head(12))

2.4.1 检查函数

总共有12列, 使用前面的 info就能发现有值的只有11列? 那么不对啊,上面命名发现 5月是NaN, 9月也没有啊? 为什么是 11列呢,其实9月不是没有值, 而是有值,只不过是个空值。

这种情况我们在Excel中可以直接找到这行给删除里面的空内容。但是如果数据量很多呢, 怎么处理呢?

序号函数说明
1isnull()返回一个布尔型的DataFrame,标记了数据中的缺失值位置。对于缺失值位置,返回True;对于非缺失值位置,返回False。
2notnull()返回一个布尔型的DataFrame,标记了数据中的非缺失值位置。对于非缺失值位置,返回True;对于缺失值位置,返回False。
3isna()isnull()的别名函数,执行相同的操作。
4notna()notnull()的别名函数,执行相同的操作。
5any()检测DataFrame或Series对象中是否存在任何缺失值。返回一个布尔值,如果存在缺失值,则为True;否则为False。
6all()检测DataFrame或Series对象中的所有值是否都是缺失值。返回一个布尔值,如果所有值都是缺失值,则为True;否则为False。
python
1# isna(): isnull()的别名函数,执行相同的操作 2# 日期 销售金额 3# 4 2023-05 NaN 4# 日期 销售金额 5# 4 2023-05 NaN 6print(df[df['销售金额'].isna()]) 7print(df[df['销售金额'].isnull()]) 8 9# 有一个满足是NaN, 5月是NaN 就返回 True 10print(df['销售金额'].isna().any()) 11# 全部满足是NaN,因为只有5月是NaN,所以就返回 False 12print(df['销售金额'].isna().all()) 13 14# 当我敲一个空格,发现可以找到 15# 日期 销售金额 16# 8 2023-09 17print(df[df['销售金额']==' ']) 18 19# 当我敲一个tab键发现就找不到了 20print(df[df['销售金额']==' '])

2.4.2 空字符检测与处理

通过前面的检查,会发现NaN的缺省值,非常好处理。但是对于那些空字符, 因为我们并不知道是几个空字符。 可能是一个空格,可能是二个空格,也可能是一个tab键,更有甚者是一个换行键。那么对于这种数据我们怎么来处理呢?

  1. 一个空格 或 多个空格
  2. 一个tab或者多个tab
  3. 一个换行或者多个换行
  4. 前面的混合出现,有空格有换行

我们的思路就是将上面的情况,全转换成空字符,然后再将空字符转换成NaN,然后就能使用前面2.4.1中的方法了

python
1# 空格替换前 Empty DataFrame (因为不知道有几个空格,所以这样找不到数据) 2print('空格替换前', df[df['销售金额'] == '']) 3 4# 不管有多个空字符都换成空字符 5df['销售金额'] = df['销售金额'].replace(' ', '') 6 7# 空格替换后 (因为空格都转换成空字符,所以这里就能找到了) 8# 日期 销售金额 9# 8 2023-09 10print('空格替换后', df[df['销售金额'] == ''])

针对于上面可能出现的所有情况, 有没有万能的办法呢? 当然有tab键其实就是 换行就是 。我们可以通过正则匹配的形式进行移除。

我们使用了str.replace()方法,并传递了匹配模式r's'。该模式表示匹配任何空字符(包括空格、换行符和制表符)。 通过将匹配模式替换为空字符串'',我们将匹配到的空字符、换行符和制表符移除。

python
1data = {'Text': [' Hello ', ' 2World 3', ' Welcome']} 4df = pd.DataFrame(data) 5 6# Text 7# 0 Hello 8# 1 9World 10 11# 2 Welcome 12print(df) 13# 移除 Text 列中的空字符、换行符和制表符 14 15df['Text'] = df['Text'].str.replace(r's', '', regex=True) 16 17# Text 18# 0 Hello 19# 1 World 20# 2 Welcome 21print(df)

然后我们在将空字符换成缺省值

python
1data = {'Text': [' 2', ' 3World 4', ' Welcome']} 5 6df = pd.DataFrame(data) 7# Text 8# 0 9 10# 1 11World 12 13# 2 Welcome 14print(df) 15 16# 移除多余的符号 17df['Text'] = df['Text'].replace(r's', '', regex=True) 18 19# 然后将空字符换成NaN 20df['Text'] = df['Text'].replace('', np.NAN) 21 22# Text 23# 0 NaN 24# 1 World 25# 2 Welcome 26print(df)

到这里我们就可以将空格等情况,全部统一处理成 NaN 了。

然后pandas里面还有一个统一处理NaN的方法,比如将所有的NaN,都换成指定的值。

python
1 2# 不管有多个空字符都换成空字符 3df['销售金额'] = df['销售金额'].replace(r's', '', regex=True) 4# 将空字符都转换成NaN 5df['销售金额'] = df['销售金额'].replace('', np.NAN) 6 7# 日期 销售金额 8# 0 2023-01 100.0 9# 1 2023-02 80.0 10# 2 2023-03 50.0 11# 3 2023-04 60.0 12# 4 2023-05 NaN 13# 5 2023-06 23.0 14# 6 2023-07 45.0 15# 7 2023-08 55.0 16# 8 2023-09 NaN 17# 9 2023-10 75.0 18# 10 2023-11 123.0 19# 11 2023-12 534.0 20print(df)

三、数据清洗

3.1 处理缺失值

3.1.1 填充指定值

前面我们已经将销售表格中的空字符都处理成了NaN,这里讲如果处理缺失值。

fillna() 是Pandas中的一个函数,用于填充(替换)数据中的缺失值。该函数可以用于Series或DataFrame对象。以下是fillna()函数的使用方法和示例:将我们的销售表格缺省值填充为0.

python
1# 将所有列的的NaN都转换成0 2df.fillna(0, inplace=True) 3 4# 填充指定列 5df['销售金额'].fillna(0, inplace=True) 6 7# 日期 销售金额 8# 0 2023-01 100.0 9# 1 2023-02 80.0 10# 2 2023-03 50.0 11# 3 2023-04 60.0 12# 4 2023-05 0.0 13# 5 2023-06 23.0 14# 6 2023-07 45.0 15# 7 2023-08 55.0 16# 8 2023-09 0.0 17# 9 2023-10 75.0 18# 10 2023-11 123.0 19# 11 2023-12 534.0 20print(df)

3.1.2 填充前一个的值

看到索引1是None,填充了他的前一个值也是1 索引值3, 也填充了他的前一个值3

python
1import pandas as pd 2 3s = pd.Series([1, None, 3, None, 5]) 4filled_s = s.fillna(method='ffill') 5 6# 0 1.0 7# 1 1.0 8# 2 3.0 9# 3 3.0 10# 4 5.0 11# dtype: float64 12print(filled_s)

3.1.3 填充后一个的值

可以看到他是向后填充的,如果最后一个值也是NaN的话,因为没有后面的值,所以不填充。

python
1s = pd.Series([1, None, 3, None, 5, None]) 2filled_s = s.fillna(method='bfill') 3 4# 0 1.0 5# 1 3.0 6# 2 3.0 7# 3 5.0 8# 4 5.0 9# 5 NaN 10print(filled_s)

3.1.4 删除缺省值

dropna() 是 Pandas 中用于删除缺失值的函数。它可以用于 Series 或 DataFrame 对象,并提供了一些参数来控制删除缺失值的方式。前面我们讲缺省值转换成了其他的值。这个函数是将缺失值直接删除。

thresh参数用法是:保留至少有n个非NaN数据的行/列

索引0 有2个非NaN的值,所以保留了 索引1 只有1个非NaN的值,所以删除了 索引2 没有非NaN的值,所以删除了

  • 如果不指定thresh, 则有NaN就删除。只有当这一行或这一列全部都是非NaN才会保留。
python
1df = pd.DataFrame({'A': [1, None, None], 'B': [6, 7, None]}) 2 3# A B 4# 0 1.0 6.0 5# 1 NaN 7.0 6# 2 NaN NaN 7print(df) 8 9# 保留至少有2个非NaN的 10# A B 11# 0 1.0 6.0 12print(df.dropna(thresh=2))

3.2 处理重复值

3.2.1 查看重复值

duplicated() 是 Pandas 中用于检测重复值的函数。它可以用于 Series 或 DataFrame 对象,并返回一个布尔类型的 Series,指示每个元素是否为重复值。

在这里插入图片描述

python
1 2df = pd.DataFrame({'A': [1, 2, 3, 2, 8, 8], 'B': [1, 6, 7, 6, 8, 8]}) 3 4# A B 5# 0 1 1 6# 1 2 6 7# 2 3 7 8# 3 2 6 9# 4 8 8 10# 5 8 8 11print(df) 12 13# 0 False 14# 1 False 15# 2 False 16# 3 True 17# 4 False 18# 5 True 19# dtype: bool 20print(df.duplicated()) 21 22# 0 False 23# 1 False 24# 2 False 25# 3 True 26# 4 False 27# 5 True 28print(df['A'].duplicated()) 29

3.2.2 删除重复值

drop_duplicates() 是 Pandas 中用于删除重复值的函数。

参数名称描述
subset指定在哪些列中检查重复值。可以是单个列名的字符串或包含多个列名的列表
keep指定保留哪个重复值。可选值包括 'first''last'False
inplace指定是否在原始对象上进行就地删除。默认为 False
ignore_index重置索引,使删除重复值后的 DataFrame 的索引连续递增
subset_keep为每个指定的列提供一个保留方式的字典。可以用于为不同的列指定不同的保留方式

在这里插入图片描述

python
1 2df = pd.DataFrame({'A': [1, 2, 3, 2, 8, 8], 'B': [1, 6, 7, 6, 8, 8]}) 3 4# A B 5# 0 1 1 6# 1 2 6 7# 2 3 7 8# 3 2 6 9# 4 8 8 10# 5 8 8 11print(df) 12 13# ------------------ 14# A B 15# 0 1 1 16# 1 2 6 17# 2 3 7 18# 4 8 8 19print(df.drop_duplicates(subset=['A'])) 20 21# ------------------ 22# A B 23# 0 1 1 24# 1 2 6 25# 2 3 7 26# 4 8 8 27print(df.drop_duplicates(subset=['A', 'B']))

上面keep不填默认删除最后一个,下面我们指定保留最后一个。删除前面的重复。

在这里插入图片描述

python
1df = pd.DataFrame({'A': [1, 2, 3, 2, 8, 8], 'B': [1, 6, 7, 6, 8, 8]}) 2 3# A B 4# 0 1 1 5# 1 2 6 6# 2 3 7 7# 3 2 6 8# 4 8 8 9# 5 8 8 10print(df) 11 12# ------------------ 13# A B 14# 0 1 1 15# 2 3 7 16# 3 2 6 17# 5 8 8 18print(df.drop_duplicates(subset=['A'], keep='last')) 19 20 21# ------------------ 22# A B 23# 0 1 1 24# 2 3 7 25# 3 2 6 26# 5 8 8 27print(df.drop_duplicates(subset=['A', 'B'], keep='last'))

3.3 异常值处理

对于异常值的处理我们有以下三种常见的解决办法。

  • 过滤:将异常值从数据中排除,不进行进一步分析。
  • 替换:使用合适的方法(例如均值、中位数等)将异常值替换为其他值,使其更符合数据分布。
  • 删除:完全删除包含异常值的行或列,如果异常值影响整体分析结果。

3.3.1 过滤

过滤的前提是我们能先发现数据问题,如下面的例子。发现是NaN的直接过滤。

python
1 2data = { 3 '角色': ['刘备', '关羽', '张飞', '赵云', '黄忠', '马超', '曹操', '孙权', '周瑜'], 4 '颜色': ['红色', '绿色', '蓝色', '', '红色', np.NAN, '蓝色', '黄色', '红色'] 5} 6 7df = pd.DataFrame(data) 8 9# 角色 颜色 10# 0 刘备 红色 11# 1 关羽 绿色 12# 2 张飞 蓝色 13# 3 赵云 14# 4 黄忠 红色 15# 5 马超 NaN 16# 6 曹操 蓝色 17# 7 孙权 黄色 18# 8 周瑜 红色 19print(df) 20 21print('------------------') 22 23# 找到空字符 或者 nan的 然后利用 ~取反, 24new_df = df[~((df['颜色'] == '') | (df['颜色'].isna()))] 25 26# ------------------ 27# 角色 颜色 28# 0 刘备 红色 29# 1 关羽 绿色 30# 2 张飞 蓝色 31# 4 黄忠 红色 32# 6 曹操 蓝色 33# 7 孙权 黄色 34# 8 周瑜 红色 35print(new_df)

3.3.2 替换

  • 找到要替换的数据规律: ((df['颜色'] == '') | (df['颜色'].isna()))
  • df.loc[条件,要替换的列] = 要替换的新值
python
1data = { 2 '角色': ['刘备', '关羽', '张飞', '赵云', '黄忠', '马超', '曹操', '孙权', '周瑜'], 3 '颜色': ['红色', '绿色', '蓝色', '', '红色', np.NAN, '蓝色', '黄色', '红色'] 4} 5 6df = pd.DataFrame(data) 7 8# 角色 颜色 9# 0 刘备 红色 10# 1 关羽 绿色 11# 2 张飞 蓝色 12# 3 赵云 13# 4 黄忠 红色 14# 5 马超 NaN 15# 6 曹操 蓝色 16# 7 孙权 黄色 17# 8 周瑜 红色 18print(df) 19 20print('------------------') 21 22# 找到空字符 或者 nan的 然后利用 ~取反, 23 24df.loc[((df['颜色'] == '') | (df['颜色'].isna())), '颜色'] = '黑色' 25 26# ------------------ 27# 角色 颜色 28# 0 刘备 红色 29# 1 关羽 绿色 30# 2 张飞 蓝色 31# 3 赵云 黑色 32# 4 黄忠 红色 33# 5 马超 黑色 34# 6 曹操 蓝色 35# 7 孙权 黄色 36# 8 周瑜 红色 37print(df)

3.3.3 条件删除

第一种方法就是前面说的, 利用取反 ~ 就可以达到删除的效果。

  • df[条件] 找到符合条件的行
  • df.drop(df[条件].index, inplace=True)
python
1df.drop(df[((df['颜色'] == '') | (df['颜色'].isna()))].index, inplace=True)

3.4 数据类型转换

如下列子,B列的数值看起来是数字,但是实际上却是字符。 当对字符类型进行sum会发现结果等于字符串拼接 100100200。 如果我们要当做数组进行处理,要使用 astype 方法, 并传入指定的类型。

3.4.1 基本类型转换

python
1df = pd.DataFrame({ 2 'A': ['2023-01', '2023-02', '2023-03'], 3 'B': ['100', '100', '200'] 4}) 5 6# # Column Non-Null Count Dtype 7# --- ------ -------------- ----- 8# 0 A 3 non-null object 9# 1 B 3 non-null object 10print(df.info()) 11# B 列相加 100100200 12print(df['B'].sum()) 13 14# 修改B列的值,为数字类型 15df['B'] = df['B'].astype(int) 16 17# # Column Non-Null Count Dtype 18# --- ------ -------------- ----- 19# 0 A 3 non-null object 20# 1 B 3 non-null int64 21print(df.info()) 22 23# B 列相加 100100200 24print(df['B'].sum())

3.4.2 日期类型转换

A列看起来是日期,我们同样进行日期转换。 通过 pd.to_datetime 按照日期格式进行转换。

日期格式类型格式字符串
年-月-日'%Y-%m-%d'
月/日/年'%m/%d/%Y'
日-月-年'%d-%m-%Y'
年/月/日 小时:分钟:秒'%Y/%m/%d %H:%M:%S'
年-月-日 小时:分钟:秒'%Y-%m-%d %H:%M:%S'
年-月-日 小时:分钟'%Y-%m-%d %H:%M'
月/日/年 小时:分钟 AM/PM'%m/%d/%Y %I:%M %p'
月/日/年 小时:分钟:秒 AM/PM'%m/%d/%Y %I:%M:%S %p'
python
1df['A'] = pd.to_datetime(df['A'], format='%Y-%m') 2 3# # Column Non-Null Count Dtype 4# --- ------ -------------- ----- 5# 0 A 3 non-null datetime64[ns] 6# 1 B 3 non-null int64 7print(df.info()) 8 9# 通过.dt获取日期 10df['year'] = df['A'].dt.year 11df['month'] = df['A'].dt.month 12df['day'] = df['A'].dt.day 13print(df)

当A类转换成日期类型后,我们就可以获取更多的时间信息。

属性描述
.dt.year年份
.dt.month月份,范围为 1 到 12
.dt.day日期,范围为 1 到 31
.dt.hour小时数,范围为 0 到 23
.dt.minute分钟数,范围为 0 到 59
.dt.second秒数,范围为 0 到 59
.dt.microsecond微秒数,范围为 0 到 999999
.dt.weekday星期几的数值,范围为 0(周一)到 6(周日)
.dt.day_name()星期几的名称
.dt.quarter季度,范围为 1 到 4
.dt.is_month_start检查日期是否为月初
.dt.is_month_end检查日期是否为月末
.dt.is_quarter_start检查日期是否为季度初
.dt.is_quarter_end检查日期是否为季度末
.dt.is_year_start检查日期是否为年初
.dt.is_year_end检查日期是否为年末

3.5 数据格式化与规范化

对于字符串类型的数据,可以使用字符串处理函数(如str.lower()、str.upper()、str.strip()等)对数据进行格式化和规范化。

python
1import pandas as pd 2 3# 创建示例数据 4data = { 5 'Name': [' John Smith ', 'Mary Johnson', ' David Brown '] 6} 7 8df = pd.DataFrame(data) 9 10# 转换为小写 11df['Lowercase'] = df['Name'].str.lower() 12 13# 转换为大写 14df['Uppercase'] = df['Name'].str.upper() 15 16# 去除首尾空格 17df['Trimmed'] = df['Name'].str.strip() 18 19# Name Lowercase Uppercase Trimmed 20# 0 John Smith john smith JOHN SMITH John Smith 21# 1 Mary Johnson mary johnson MARY JOHNSON Mary Johnson 22# 2 David Brown david brown DAVID BROWN David Brown 23print(df) 24

四、数据预处理

4.1 特征选择与删除

4.1.1 特征选择

什么是特征选择,比如一个Excel中有多列的数据, 但是我们只需要某些列。那么我们就可以选择指定的列进行使用。

  • df[['A','B']] or df['A']
  • df.loc[1:3,'A'] loc可以选择具体的索引,比如就选择索引从1-3的
python
1# 创建示例数据 2data = { 3 '年龄': [25, 30, 35, 40], 4 '性别': ['男', '女', '男', '女'], 5 '收入': [50000, 60000, 70000, 80000], 6 '购买历史': ['是', '否', '是', '否'], 7 '目标': [1, 0, 1, 0] 8} 9 10df = pd.DataFrame(data) 11 12# 特征选择与删除 13selected_features = ['年龄', '收入', '购买历史'] # 选择与购买行为相关的特征 14df_selected = df[selected_features] 15 16# 年龄 收入 购买历史 17# 0 25 50000 是 18# 1 30 60000 否 19# 2 35 70000 是 20# 3 40 80000 否 21print(df_selected) 22 23 24# 年龄 收入 购买历史 25# 1 30 60000 否 26# 2 35 70000 是 27# 3 40 80000 否 28print(df.loc[1:3, selected_features])

4.2 数据转换与衍生

4.2.1 衍生-增加列

这个例子,前面已经说过。就是日期的例子。参考: 3.4.2 日期类型转换, 很方便的添加列。

python
1df['A'] = pd.to_datetime(df['A'], format='%Y-%m') 2 3# # Column Non-Null Count Dtype 4# --- ------ -------------- ----- 5# 0 A 3 non-null datetime64[ns] 6# 1 B 3 non-null int64 7print(df.info()) 8 9# 通过.dt获取日期 10df['year'] = df['A'].dt.year 11df['month'] = df['A'].dt.month 12df['day'] = df['A'].dt.day 13print(df)

4.2.2 衍生-增加行

len() 是查看行数, 因为len的返回值是从1开始的,所以每次正好是最后一行。利用这个特性 来新增一行。

python
1import pandas as pd 2 3# 创建空的 DataFrame 4df = pd.DataFrame(columns=['Name', 'Age', 'Gender']) 5 6# 方法一: 通过索引的方式增加行,值按照顺序 姓名,爱好 7df.loc[len(df)] = ['诸葛庐', '计谋'] 8 9# 方法二: 通过索引的方式增加行,值根据字典来指定 10df.loc[len(df)] = {'爱好': '哭', '姓名': '刘备'} 11 12# 打印结果 13# 姓名 爱好 14# 0 张飞 喝酒 15# 1 朱元璋 你猜 16# 2 周杰伦 喝奶茶 17# 3 诸葛庐 计谋 18# 4 刘备 哭 19print(df) 20 21# 老版本还可以使用 append 进行追加。新版这个方法已经废弃。官方建议使用 concat 22# https://pandas.pydata.org/docs/whatsnew/v1.4.0.html?highlight=append 23df3 = pd.concat([df, df], ignore_index=True) 24 25# 姓名 爱好 26# 0 张飞 喝酒 27# 1 朱元璋 你猜 28# 2 周杰伦 喝奶茶 29# 3 诸葛庐 计谋 30# 4 刘备 哭 31# 5 张飞 喝酒 32# 6 朱元璋 你猜 33# 7 周杰伦 喝奶茶 34# 8 诸葛庐 计谋 35# 9 刘备 哭 36print(df3)

注意: 老版本还可以使用 append 进行追加。新版这个方法已经废弃。官方建议使用 concat 在这里插入图片描述

4.3 数据合并与拆分

4.3.1 数据合并

假设我们有两个数据集,一个包含客户信息,另一个包含订单信息。我们希望将这两个数据集根据客户ID进行合并,以便分析客户的订单行为。

  • 主要用到merge方法

以下是merge()方法中常用参数的补全,包括可选值和默认值:

参数说明可选值默认值
left左侧的DataFrame,要进行合并的左侧数据集。DataFrame
right右侧的DataFrame,要进行合并的右侧数据集。DataFrame
how合并方式,指定如何对齐和合并数据。'inner', 'outer', 'left', 'right''inner'
on列名或列名列表,用于指定进行合并的列。列名或列名列表 ,如果要关联的名称两笔都一样,可以直接用on
left_on左侧DataFrame中用于合并的列。列名或列名列表,如果要关联的名称不一样,可以使用这个。支持列表参数
right_on右侧DataFrame中用于合并的列。列名或列名列表,如果要关联的名称不一样,可以使用这个。支持列表参数
suffixes用于解决合并后列名冲突的后缀。元组或列表('_x', '_y')

如果你看不懂 how 的参数,可以参考下图。 在这里插入图片描述

python
1 2import pandas as pd 3 4# 客户信息数据集 5customer_data = { 6 '客户ID': ['001', '002', '003'], 7 '姓名': ['张三', '李四', '王五'], 8 '年龄': [25, 30, 35] 9} 10df_customer = pd.DataFrame(customer_data) 11 12# 订单信息数据集 13order_data = { 14 '客户ID': ['001', '002', '003'], 15 '订单号': ['A001', 'A002', 'A003'], 16 '金额': [100, 200, 150] 17} 18df_order = pd.DataFrame(order_data) 19 20# 数据合并,如果学过数据库,就会发现其实join 21df_merged = pd.merge(df_customer, df_order, on='客户ID') 22 23# 打印合并结果 24# 客户ID 姓名 年龄 订单号 金额 25# 0 001 张三 25 A001 100 26# 1 002 李四 30 A002 200 27# 2 003 王五 35 A003 150 28print(df_merged) 29

4.3.2 数据拆分

可以参考 4.1.1 特征选择

  • df[列名]
  • loc[:,列]

4.4 数据重塑与透视

4.4.1 数据重塑-宽数据转长数据

melt() 方法用于将宽格式的DataFrame转换为长格式,也称为"unpivot"操作。下面是melt()方法的参数及其说明:

参数说明
frame要进行转换的DataFrame。
id_vars保持不变的列,即转换后的长格式中的标识符列。
value_vars要转换的列,即转换后的长格式中的值列。
var_name用于标识值列的名称列的名称。
value_name用于标识值的列的名称。

在这里插入图片描述

python
1import pandas as pd 2 3# 销售数据集 4sales_data = { 5 '产品': ['A', 'B'], 6 '销售额1月': [1000, 2000], 7 '销售额2月': [1500, 1800], 8 '销售额3月': [1200, 2300] 9} 10df_sales = pd.DataFrame(sales_data) 11 12print(df_sales) 13 14print('------------') 15# 数据拆分 16df_long = pd.melt(df_sales, id_vars=['产品'], var_name='月份', value_name='销售额') 17 18# 打印拆分结果 19print(df_long) 20 21# 假如我不想要销售额3月的数据,还可以通过 `value_vars` 来执行。 22df_long = pd.melt(df_wide, id_vars=['产品'],value_vars=['销售额1月', '销售额2月'], 23 var_name='月份', value_name='销售额') 24 25# 打印转换结果 26# 产品 月份 销售额 27# 0 A 销售额1月 1000 28# 1 B 销售额1月 2000 29# 2 A 销售额2月 1500 30# 3 B 销售额2月 1800 31print(df_long)

4.4.2 数据透视

数据透视是一种数据处理技术,用于将原始数据重新组织和汇总,以便更好地理解和分析数据的关系和趋势。透视表是数据透视的一种常见形式,它将数据按照指定的行和列进行分组,并对其中的数值进行聚合计算。 通过数据透视,您可以根据自己的需求和分析目标,对数据进行灵活的重塑和汇总,以便从不同的角度和维度观察和理解数据。

如下我们会用到下面这些函数。

  • pivot
  • pivot_table
  • groupby

下面我们演示如下数据, 产品每个月的销售额。

python
1import pandas as pd 2 3# 销售数据集 4sales_data = { 5 '产品': ['A', 'A', 'B', 'B', 'A', 'B'], 6 '月份': ['一月', '二月', '一月', '二月', '三月', '三月'], 7 '销售额': [1000, 1500, 2000, 1800, 1200, 2300] 8} 9df_sales = pd.DataFrame(sales_data) 10 11# 产品 月份 销售额 12# 0 A 一月 1000 13# 1 A 二月 1500 14# 2 B 一月 2000 15# 3 B 二月 1800 16# 4 A 三月 1200 17# 5 B 三月 2300 18print(df_sales)

我们想分析下,每个产品每月的销售额。这种情况我们的维度其实就是

  • 维度: 产品 + 月份 指标: sum(销售额)

index + columns 都是维度,不同的是index放在列,columns 是行。

在这里插入图片描述

python
1# 月份 一月 三月 二月 2# 产品 3# A 1000 1200 1500 4# B 2000 2300 1800 5print(df_sales.pivot(index='产品', columns='月份', values='销售额'))

以上就是 pivot函数。还有一个pivot_table。

pivot_table()和pivot()都是Pandas中用于数据重塑和透视的函数,但它们之间存在一些区别。 pivot_table()函数是一个通用的透视表函数,可以处理具有重复索引值的数据,并允许使用聚合函数对重复值进行汇总计算。

注意: pivot 不能处理重复值, 及维度和指标如果是重复的则会报错。pivot_table则可以处理重复值,且可以对指标进行计算。

参数说明
data要进行透视表操作的数据集。
values用于聚合的列,即要进行透视和计算的值列。
index用于分组的列或列列表,即透视表的行索引。
columns用于分组的列或列列表,即透视表的列索引。
aggfunc聚合函数或函数列表,用于对重复值进行聚合操作,默认为np.mean
fill_value替换缺失值的值。
margins是否显示行和列的汇总统计,默认为False
margins_name汇总统计的行和列的标签名称。
python
1# 透视表操作 2# 月份 一月 三月 二月 总金额 3# 产品 4# A 1000 1200 1500 3700 5# B 2000 2300 1800 6100 6# 总金额 3000 3500 3300 9800 7df_pivot = df_sales.pivot_table(index='产品', columns='月份', values='销售额', aggfunc='sum', margins=True, 8 margins_name="总金额")

如果对编程有经验的同学会发现这其实就是数据分组,按照一定的分组分组,分组后的数据进行数据计算。 所以如果要统计产品和月份每月的销售额。其实groupby方法也可以实现。

python
1# 月份 产品 2# 一月 A 1000 3# B 2000 4# 三月 A 1200 5# B 2300 6# 二月 A 1500 7# B 1800 8groupby = df_sales.groupby(by=['月份', '产品'])['销售额'].sum()

在本系列文章中,我们会从实战出发,深入探讨了Pandas数据分析库的众多功能和强大之处。掌握使用Pandas进行数据处理、清洗和分析的基本技巧。全系列课程均是免费。你的关注是我继续的动力。