1.Pandas简介

1.1 Pandas是什么?

Pandas 是 Python 数据分析工具链中最核心的库,充当数据读取、清洗、分析、统计、输出的高效工具。
Pandas 是一个开源的数据分析和数据处理库,它是基于 Python 编程语言的。
Pandas 提供了易于使用的数据结构和数据分析工具,特别适用于处理结构化数据,如表格型数据(类似于Excel表格)。
Pandas 是数据科学和分析领域中常用的工具之一,它使得用户能够轻松地从各种数据源中导入数据,并对数据进行高效的操作和分析。
Pandas是基于NumPy构建的专门为处理表格和混杂数据设计的Python库,其核心设计理念包括:
• 标签化数据结构:提供带标签的轴(行索引和列名)
• 灵活处理缺失数据:内置NaN处理机制
• 智能数据对齐:自动按标签对齐数据
• 强大IO工具:支持从CSV、Excel、SQL等20+数据源读写
• 时间序列处理:原生支持日期时间处理和频率转换

名称由来
pandas这个名字源于panel data(面板数据,这是多维结构化数据集在计量经济学中的术语)以及Python data analysis(Python数据分析)。

pandas兼具numpy高性能的数组计算功能以及电子表格和关系型数据库(如SQL)灵活的数据处理功能。它提供了复杂精细的索引功能,能更加便捷地完成重塑、切片和切块、聚合以及选取数据子集等操作。

pandas功能:
• 有标签轴的数据结构
在数据结构中,每个轴都被赋予了特定的标签,这些标签用于标识和引用轴上的数据元素,使得数据的组织、访问和操作更加直观和方便

应用场景

工具功能特色适用场景
Excel图形界面,简单上手人工分析、小规模数据
SQL高效读写,最终数据源数据库查询和联表
Python + Pandas算法和分析部署核心数据清洗,统计分析,可视化等
  1. 与Excel对比:
    ○ 优势:▪ 处理百万级数据不卡顿(Excel约100万行限制)▪ 可复用的分析流程(脚本 vs 手工操作)▪ 支持复杂数据转换(如:分组聚合、时间重采样)
    ○ 局限:▪ 可视化交互性较弱▪ 学习曲线较陡峭

  2. 与数据库对比:
    ○ 优势:▪ 无需SQL知识即可分析▪ 适合探索性分析(即时反馈)▪ 丰富的数据清洗函数
    ○ 局限:▪ 数据量受内存限制▪ 不适合高并发访问

  3. 与纯Python代码对比:
    ○ 优势:▪ 向量化运算比for循环快10-100倍▪ 内置统计分析方法(如:相关系数计算)▪ 丰富的数据透视功能
    ○ 局限:▪ 需要额外学习Pandas API

在这里插入图片描述
行业洞见:根据2023年Kaggle调查,Pandas是数据科学家使用率最高的工具(占比93%),远超第二名Excel(占比32%)

1.2 了解 Pandas 核心数据结构:Series 和 DataFrame

Pandas 基于 Numpy,并提供了 2 大核心数据结构:
• Series:一维带有标签的数组
• DataFrame:二维表格结构,可看作多个 Series 的组合

用得最多的pandas对象是Series,一个一维的标签化数组对象,另一个是DataFrame,它是一个面向列的二维表结构。

特性SeriesDataFrame
维度一维二维
索引单索引行索引 + 列名
数据存储同质化数据类型各列可不同数据类型
类比Excel 单列整张 Excel 工作表
创建方式pd.Series([1, 2, 3])pd.DataFrame({'col': [1, 2, 3]})

在这里插入图片描述
在这里插入图片描述
Pandas 与 Numpy 的关系与区别
就像学习数学要先掌握算术才能学代数一样,NumPy就是数据分析的"算术基础"。虽然可以直接用计算器(Pandas),但理解底层原理才能走得更远。

2. 核心数据结构:Series

2.1 创建与访问

什么是Series

类似于 NumPy 一维数组,但增加了 “标签”,可以理解为「一维标签化数组」
Series 是 Pandas 中的一个核心数据结构,类似于一个一维的数组,具有数据和索引。
Series 可以存储任何数据类型(整数、浮点数、字符串等),并通过标签(索引)来访问元素。Series 的数据结构是非常有用的,因为它可以处理各种数据类型,同时保持了高效的数据操作能力,比如可以通过标签来快速访问和操作数据。
在这里插入图片描述
Series 特点:
• 一维数组:Series 中的每个元素都有一个对应的索引值。
• 索引: 每个数据元素都可以通过标签(索引)来访问,默认情况下索引是从 0 开始的整数,但你也可以自定义索引。
• 数据类型: Series 可以容纳不同数据类型的元素,包括整数、浮点数、字符串、Python 对象等。
• 大小不变性:Series 的大小在创建后是不变的,但可以通过某些操作(如 append 或 delete)来改变。
• 操作:Series 支持各种操作,如数学运算、统计分析、字符串处理等。
• 缺失数据:Series 可以包含缺失数据,Pandas 使用NaN(Not a Number)来表示缺失或无值。
• 自动对齐:当对多个 Series 进行运算时,Pandas 会自动根据索引对齐数据,这使得数据处理更加高效。

我们可以使用 Pandas 库来创建一个 Series 对象,并且可以为其指定索引(Index)、名称(Name)以及值(Values):

Python
import pandas as pd
s = pd.Series([10, 20, 30], index=["a", "b", "c"])

创建Series

直接通过列表创建Series

Python
import pandas as pd
s = pd.Series([4, 7, -5, 3])
print(s)
# 0    4
# 1    7
# 2   -5
# 3    3
# dtype: int64

Series的字符串表现形式为:索引在左边,值在右边。由于我们没有为数据指定索引,于是会自动创建一个0到N-1(N为数据的长度)的整数型索引。

• 通过列表创建Series时指定索引

Python
s = pd.Series([4, 7, -5, 3], index=["a", "b", "c", "d"])
print(s)
# a    4
# b    7
# c   -5
# d    3
# dtype: int64

• 通过列表创建Series时指定索引和名称

Python
s = pd.Series([4, 7, -5, 3], index=["a", "b", "c", "d"],name="hello_python")
print(s)
# a    4
# b    7
# c   -5
# d    3
# Name: hello_python, dtype: int6

名称的作用,与变量名的区别
在 Pandas 的 Series 中,name 参数用于给整个 Series 对象赋予一个名称。这个名称有以下几个用途:

  1. 标识作用
    • name 可以作为 Series 的标识,类似于给数据列取一个名字。
    • 当你打印 Series 时,name 会显示在输出的最下方(如你的例子所示)。

  2. DataFrame 列名
    • 如果你将一个 Series 转换成 DataFrame 或与其他 DataFrame 合并,name 会自动成为列名。
    • 例如:

Python
df = s.to_frame()  # 转换为 DataFrame,列名就是 "hello_python"
print(df)

输出:
Plain Text
   hello_python
a             4
b             7
c            -5
d             3

  1. 对齐操作
    • 在 Pandas 运算(如 concat、merge 等)时,name 可以帮助对齐数据。
  2. 导出数据
    • 当你将 Series 导出为 CSV 或其他格式时,name 会成为列名。

name 的主要作用是 给 Series 一个标识,方便后续数据处理、合并或导出。如果只是单独使用 Series,name 可能看起来作用不大,但在更复杂的数据操作中(如 DataFrame 整合),它会很有用。

• 直接通过字典创建Series

Python
dic = {"a": 4, "b": 7, "c": -5, "d": 3}
s = pd.Series(dic)
print(s)
# a    4
# b    7
# c   -5
# d    3
# dtype: int64
s1 = pd.Series(dic,index=["a","c"],name="aacc")
print(s1)
# a    4
# c   -5
# Name: aacc, dtype: int64

Series的常用属性

属性说明
indexSeries 的索引对象
valuesSeries 的值
dtype 或 dtypesSeries 的元素类型
shapeSeries 的形状
ndimSeries 的维度
sizeSeries 的元素个数
nameSeries 的名称
loc[]显式索引,按标签索引或切片
iloc[]隐式索引,按位置索引或切片
at[]使用标签访问单个元素
iat[]使用位置访问单个元素
Python
import pandas as pd
arrs = pd.Series([11,22,33,44,55],name="atguigu",index=["a","b","c","d","e"])
# print(arrs)
# index Series的索引对象
print(arrs.index)
for i in arrs.index:
    print(i)
print(arrs.values) # values    Series的值
print(arrs.ndim)  # ndim  Series的维度
print(arrs.shape)  # shape Series的形状
print(arrs.size) # size  Series的元素个数
# dtype或dtypes  Series的元素类型
print(arrs.dtype)
print(arrs.dtypes)
# name  Series的名称
print(arrs.name)
# loc[] 显式索引,按标签索引或切片
print(arrs.loc["c"])
print(arrs.loc["c":"d"])
# iloc[]    隐式索引,按位置索引或切片
print(arrs.iloc[0])
print(arrs.iloc[0:3])
# at[]  使用标签访问单个元素 不支持切片
print(arrs.at["a"])
# iat[] 使用位置访问单个元素 不支持切片
print(arrs.iat[3])

访问Series数据

以下是 Pandas 中访问 Series 数据的主要方法汇总表格:

方法分类语法示例描述返回值是否支持切片/布尔索引
位置索引s.iloc[0]通过整数位置访问(从 0 开始)标量值
s.iloc[1:3]位置切片(左闭右开)Series
标签索引s.loc['a']通过索引标签访问标量值
s.loc[['a','b']]通过标签列表访问Series
直接索引s[0]类似 iloc(当索引非整数时可能混淆)标量值 / Series
s['a']类似 loc(优先标签索引)
布尔索引s[s > 3]通过布尔条件筛选Series
s[~(s > 3)]取反条件
函数访问s.at['a']快速访问单个标签(类似 loc 但效率更高)标量值
s.iat[0]快速访问单个位置(类似 iloc 但效率更高)
头部/尾部s.head(3)访问前 N 行(默认 5)Series
s.tail(2)访问后 N 行(默认 5)
取唯一值s.unique()返回唯一值数组ndarray
值计数s.value_counts()统计各值出现次数Series
  1. 优先使用**loc****/**iloc:直接索引[]的行为可能因索引类型不同而变化,明确场景时建议显式使用loc(标签)或iloc(位置)。
  2. 切片差异:
    ○ loc切片为闭区间(包含两端)
    ○ iloc切片为左闭右开(与Python列表一致)
  3. 布尔索引:常用于条件过滤,如s[s > 3 & s < 10]。
Python
s = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])
# 位置索引
print(s.iloc[0])  # 10
# 标签访问
s["a"]    
# 标签索引
print(s.loc['b'])  # 20
# 布尔索引
print(s[s > 25])  # c:30, d:40
# 花式索引
print(s[['a', 'c']])  # a:10, c:30

#使用布尔索引从Series中筛选满足某些条件的值
bools = s > s.mean()  # 将大于平均值的元素标记为 True
print(bools)
# a    False
# b     True
# c     True
# d    False
# dtype: bool
print(s[bools])
# b    3.5
# c    6.8
# dtype: float64
# 使用where过滤
print(s.where(s > 20, -1))  # 小于等于20的值替换为-1

2.2 Series的运算

Plain Text
s1 = pd.Series([1, 2, 3, 4])
s2 = pd.Series([10, 20, 30, 40])
# 基本运算
print(s1 + s2)  # 对应位置相加
print(s1 * 2)   # 标量乘法

2.3 常用方法与统计

用途分类方法说明示例代码
数据预览head()查看前 n 行数据,默认 5 行s.head(3)
数据预览tail()查看后 n 行数据,默认 5 行s.tail(2)
条件判断isin()判断元素是否包含在参数集合中s.isin([1, 2])
缺失值处理isna()判断是否为缺失值(如 NaN 或 None)s.isna()
聚合统计sum()求和,自动忽略缺失值s.sum()
聚合统计mean()平均值s.mean()
聚合统计min()最小值s.min()
聚合统计max()最大值s.max()
聚合统计var()方差s.var()
聚合统计std()标准差s.std()
聚合统计median()中位数s.median()
聚合统计mode()众数(可返回多个)s.mode()
聚合统计quantile(q)分位数,q 取 0~1 之间s.quantile(0.25)
聚合统计describe()常见统计信息(count、mean、std、min、25%、50%、75%、max)s.describe()
频率统计value_counts()每个唯一值的出现次数s.value_counts()
频率统计count()非缺失值数量s.count()
频率统计nunique()唯一值个数(去重)s.nunique()
唯一处理unique()获取去重后的值数组s.unique()
唯一处理drop_duplicates()去除重复项s.drop_duplicates()
抽样分析sample()随机抽样s.sample(2)
排序操作sort_index()按索引排序s.sort_index()
排序操作sort_values()按值排序s.sort_values()
替换值replace()替换值s.replace({1: 100})
转换结构to_frame()将 Series 转为 DataFrames.to_frame()
比较判断equals()判断两个 Series 是否完全相等s1.equals(s2)
信息提取keys()返回 Series 的索引对象s.keys()
统计关系corr()计算相关系数(默认皮尔逊)s1.corr(s2)
统计关系cov()协方差s1.cov(s2)
可视化hist()绘制直方图(需安装 matplotlib)s.hist()
遍历操作items()返回索引和值的迭代器for i, v in s.items(): print(i, v)
Python
import pandas as pd
import numpy as np
arrs = pd.Series([11,22,np.nan,None,44,22],index=['a','b','c','d','e','f'])
# head()    查看前n行数据,默认5行
print(arrs.head())
# tail()    查看后n行数据,默认5行
print(arrs.tail(3))
# describe()    常见统计信息
print(arrs.describe())
# count()   非缺失值元素的个数
print(arrs.count())
# keys()    返回Series的索引对象
print(arrs.index)
print(arrs.keys())
# isin()    判断数组中的每一个元素是否包含在参数集合中
print(arrs.isin([11]))
# isna()    元素是否为缺失值
print(arrs.isna())

#统计
# sum() 求和,会忽略 Series 中的缺失值
print(arrs.sum())
# mean()    平均值
print(arrs.mean())
# min() 最小值
print(arrs.min())
# max() 最大值
print(arrs.max())
# var() 方差 每个元素与平均值的差 的平方 的和
print(arrs.var())
# std() 标准差 方差的平方根
print(arrs.std())
# print(arrs.var())
# median()  中位数
# 若数据集的元素个数为奇数,中位数就是排序后位于中间位置的数值。
# 若数据集的元素个数为偶数,中位数则是排序后中间两个数的平均值。
# 去除缺失值之后,arrs 就变成了 [11, 22, 44, 22]。
# 对 [11, 22, 44, 22] 进行排序,得到 [11, 22, 22, 44]
print(arrs.median())
# mode()    众数
print(arrs.mode())
# quantile()    指定位置的分位数,如quantile(0.5)
# 分位数:分位数是把一组数据按照从小到大的顺序排列后,分割成若干等份的数值点。
# 0.25 分位数就是将数据从小到大排序后,位于 25% 位置处的数值。
# 插值方法:当计算分位数时,若位置不是整数,就需要借助插值方法来确定分位数值。# "midpoint" 插值方法是指当分位数位置处于两个数据点之间时,取这两个数据点的
# 平均值作为分位数值。
# 对于有 n个数据点的有序数据集,q分位数的位置 i可以通过公式 i=(n−1)q来计
# 算。这里 n=4,q=0.25,则 i=(4−1)×0.25=0.75。这意味着 0.25 分位数处于第一个# 数据点(值为 11)和第二个数据点(值为 22)之间。使用 "midpoint" 插值方法,
# 分位数值就是这两个数据点的平均值,即 (11+22)÷2=16.5
print(arrs.quantile(0.25, interpolation="midpoint"))


print(len(arrs))
# drop_duplicates() 去重  这里可以看出,底层None也作为NaN处理
print(arrs.drop_duplicates())
# unique()  去重后的数组
print(arrs.unique())
# nunique() 去重后非缺失值元素元素个数
print(arrs.nunique())
# sample()  随机采样
print(arrs.sample())
# value_counts()    每个元素的个数
print(arrs.value_counts())

# sort_index()  按索引排序
print(arrs.sort_index())

# sort_values() 按值排序
print(arrs.sort_values())
# replace() 用指定值代替原有值
print(arrs.replace(22,"haha"))

# to_frame()    将Series转换为DataFrame
print(arrs.to_frame())

# equals()  判断两个Series是否相同
arr1 = pd.Series([1,2,3])
arr2 = pd.Series([1,2,3])
print(arr1.equals(arr2))

# corr()    计算与另一个Series的相关系数
# arr1.corr(arr2):由于 arr1 和 arr2 的值完全相同,它们之间是完全正相关的,
#因此相关系数为 1。
# arr1.corr(arr3):arr1 的值是递增的,而 arr3 的值是递减的,它们之间是完全
# 负相关的,所以相关系数为 -1。
# arr1.corr(arr4):arr1 和 arr4 的值都是递增的,且变化趋势一致,它们之间是
# 完全正相关的,相关系数为 1。
# arr5.corr(arr6):arr5 和 arr6 的值之间没有明显的线性关系,它们的相关系数
# 为 0。
arr3 = pd.Series([3,2,1])
arr4 = pd.Series([6,7,8])
arr5 = pd.Series([1, -1, 1, -1])
arr6 = pd.Series([1, 1, -1, -1])
print(arr1.corr(arr2))
print(arr1.corr(arr3))
print(arr1.corr(arr4))
print(arr5.corr(arr6))

# cov() 计算与另一个Series的协方差
# 协方差用于衡量两个变量的总体误差,其值的正负表示两个变量的变化方向关系:
# 正值表示同向变化,负值表示反向变化。
print(arr1.cov(arr3))

2.4 统计实例

学生成绩统计

创建一个包含10名学生数学成绩的Series,成绩范围在50-100之间。计算平均分、最高分、最低分,并找出高于平均分的学生人数。

Python
import pandas as pd
import numpy as np

# 生成随机成绩
np.random.seed(42)
scores = pd.Series(np.random.randint(50, 101, 10), 
                  index=['学生'+str(i) for i in range(1, 11)])

# 计算统计量
mean_score = scores.mean()
max_score = scores.max()
min_score = scores.min()
above_avg = scores[scores > mean_score].count()

print(f"平均分: {mean_score:.1f}")
print(f"最高分: {max_score}")
print(f"最低分: {min_score}")
print(f"高于平均分的学生人数: {above_avg}")

温度数据分析

给定某城市一周每天的最高温度Series,完成以下任务:
找出温度超过30度的天数
计算平均温度
将温度从高到低排序
找出温度变化最大的两天

Python
temperatures = pd.Series([28, 31, 29, 32, 30, 27, 33], 
                         index=['周一', '周二', '周三', '周四', '周五', '周六', '周日'])

# 1. 找出温度超过30度的天数
hot_days = temperatures[temperatures > 30].count()

# 2. 计算平均温度
avg_temp = temperatures.mean()

# 3. 将温度从高到低排序
sorted_temp = temperatures.sort_values(ascending=False)

# 4. 找出温度变化最大的两天
temp_diff = temperatures.diff().abs()
max_diff_days = temp_diff.nlargest(2).index.tolist()

print(f"超过30度的天数: {hot_days}")
print(f"平均温度: {avg_temp:.1f}")
print("温度排序:\n", sorted_temp)
print(f"温度变化最大的两天: {max_diff_days}")

股票价格分析

给定某股票连续10个交易日的收盘价Series:
计算每日收益率(当日收盘价/前日收盘价 - 1)
找出收益率最高和最低的日期
计算波动率(收益率的标准差)

Python
prices = pd.Series([102.3, 103.5, 105.1, 104.8, 106.2, 107.0, 106.5, 108.1, 109.3, 110.2],
                  index=pd.date_range('2023-01-01', periods=10))

# 1. 计算每日收益率
returns = prices.pct_change()

# 2. 找出收益率最高和最低的日期
max_return_date = returns.idxmax()
min_return_date = returns.idxmin()

# 3. 计算波动率
volatility = returns.std()

print("每日收益率:\n", returns)
print(f"收益率最高的日期: {max_return_date}")
print(f"收益率最低的日期: {min_return_date}")
print(f"波动率: {volatility:.4f}")

销售数据分析

某产品过去12个月的销售量Series:
计算季度平均销量(每3个月为一个季度)
找出销量最高的月份
计算月环比增长率
找出连续增长超过2个月的月份

Python
sales = pd.Series([120, 135, 145, 160, 155, 170, 180, 175, 190, 200, 210, 220],
                 index=pd.date_range('2022-01-01', periods=12, freq='M'))

# 1. 计算季度平均销量
quarterly_avg = sales.resample('Q').mean()

# 2. 找出销量最高的月份
max_sales_month = sales.idxmax()

# 3. 计算月环比增长率
mom_growth = sales.pct_change()

# 4. 找出连续增长超过2个月的月份
growth_mask = mom_growth > 0
consecutive_growth = growth_mask.rolling(3).sum() >= 2
growth_months = sales[consecutive_growth].index

print("季度平均销量:\n", quarterly_avg)
print(f"销量最高的月份: {max_sales_month}")
print("月环比增长率:\n", mom_growth)
print("连续增长超过2个月的月份:", growth_months.tolist())

数据合并与计算

有两个Series分别记录了某产品在两个城市的日销量:
计算两个城市的总日销量
找出哪个城市的销量更高
计算两个城市销量的相关系数

Python
city_a = pd.Series([120, 135, 140, 130, 145],
                  index=pd.date_range('2023-01-01', periods=5))
city_b = pd.Series([110, 125, 150, 140, 130],
                  index=pd.date_range('2023-01-01', periods=5))

# 1. 计算两个城市的总日销量
total_sales = city_a + city_b

# 2. 找出哪个城市的销量更高
city_a_total = city_a.sum()
city_b_total = city_b.sum()
higher_sales_city = 'A' if city_a_total > city_b_total else 'B'

# 3. 计算两个城市销量的相关系数
correlation = city_a.corr(city_b)

print("总日销量:\n", total_sales)
print(f"总销量更高的城市: {higher_sales_city}")
print(f"两个城市销量的相关系数: {correlation:.2f}")

3. 核心数据结构:DataFrame

3.1 创建与访问

什么是DateFrame?

DataFrame 是 Pandas 中的核心数据结构之一,多行多列表格数据,类似于 Excel 表格 或 SQL 查询结果。
它是一个 二维表格结构,具有行索引(index)和列标签(columns)。

Python
df = pd.DataFrame({
    "name": ["Alice", "Bob"],
    "score": [90, 80]
})

在这里插入图片描述
DataFrame中的数据是以一个或多个二维块存放的(而不是列表、字典或别的一维数据结构)。它可以被看做由Series组成的字典(共同用一个索引)。提供了各种功能来进行数据访问、筛选、分割、合并、重塑、聚合以及转换等操作,广泛用于数据分析、清洗、转换、可视化等任务。
在这里插入图片描述

DataFrame的创建

Python
# 通过series来创建
import pandas as pd
import numpy as np
np.random.seed(42)
s1 = pd.Series(np.random.randint(0,10,6))
np.random.seed(41)
s2 = pd.Series(np.random.randint(0,20,6))
df = pd.DataFrame({"s1":s1,"s2":s2})

直接通过字典创建DataFrame

Python
import pandas as pd
df = pd.DataFrame({    "name": ["Alice", "Bob"],    "score": [90, 80]})
print(df)
df = pd.DataFrame({"id": [101, 102, 103], 
"name": ["张三", "李四", "王五"], "age": [20, 30, 40]})
print(df)
#     id name  age
# 0  101   张三   20
# 1  102   李四   30
# 2  103   王五   40

通过字典创建时指定列的顺序和行索引

Python
df = pd.DataFrame(
    data={"age": [20, 30, 40], 
    "name": ["张三", "李四", "王五"]}, 
    columns=["name", "age"], index=[101, 102, 103]
)
print(df)
#     name  age
# 101   张三   20
# 102   李四   30
# 103   王五   40

常用属性

属性说明
indexDataFrame 的行索引
columnsDataFrame 的列标签
valuesDataFrame 的值
ndimDataFrame 的维度
shapeDataFrame 的形状
sizeDataFrame 的元素个数
dtypesDataFrame 的元素类型
T行列转置
loc[]显式索引,按行列标签索引或切片
iloc[]隐式索引,按行列位置索引或切片
at[]使用行列标签访问单个元素
iat[]使用行列位置访问单个元素
Python
import pandas as pd
df = pd.DataFrame(data={"id": [101, 102, 103], "name": ["张三", "李四", "王五"], "age": [20, 30, 40]},index=["aa", "bb", "cc"])
# index DataFrame的行索引
print(df.index)
# columns   DataFrame的列标签
print(df.columns)
# values    DataFrame的值
print(df.values)
# ndim  DataFrame的维度
print(df.ndim)
# shape DataFrame的形状
print(df.shape)
# size  DataFrame的元素个数
print(df.size)
# dtypes    DataFrame的元素类型
print(df.dtypes)
# T 行列转置
print(df.T)
# loc[] 显式索引,按行列标签索引或切片 逗号前是行切片规则,后是列切片规则
print(df.loc["aa":"cc"])
print(df.loc[:,["id","name"]])
# iloc[]    隐式索引,按行列位置索引或切片
print(df.iloc[0:1])
print(df.iloc[0:3,2])
print("----------")
# at[]  使用行列标签访问单个元素
print(df.at["aa","name"])
# iat[] 使用行列位置访问单个元素
print(df.iat[0,1])

获取DataFrame数据

方法分类语法示例描述返回值类型是否支持切片/条件索引
列选择df['col']选择单列(返回Series)Series
df[['col1', 'col2']]选择多列(返回DataFrame)DataFrame
行选择df.loc[row_label]通过行标签选择单行(返回Series)Series✅(标签切片)
df.loc[start:end]通过标签切片选择多行(闭区间)DataFrame
df.iloc[row_index]通过行位置选择单行(从0开始)Series✅(位置切片)
df.iloc[start:end]通过位置切片选择多行(左闭右开)DataFrame
行列组合选择df.loc[row_labels, col_labels]通过标签选择行和列(如df.loc['a':'b', ['col1','col2']]Series/DataFrame
df.iloc[row_idx, col_idx]通过位置选择行和列(如df.iloc[0:2, [1,3]]Series/DataFrame
条件筛选df[df['col'] > 3]通过布尔条件筛选行DataFrame
df.query("col1 > 3 & col2 < 10")使用表达式筛选(需字符串表达式)DataFrame
快速访问df.at[row_label, 'col']快速访问单个值(标签索引,高效)标量值
df.iat[row_idx, col_idx]快速访问单个值(位置索引,高效)标量值
头部/尾部df.head(n)返回前n行(默认5)DataFrame
df.tail(n)返回后n行(默认5)DataFrame
样本抽样df.sample(n=3)随机抽取n行DataFrame
索引重置df.reset_index()重置索引(原索引变为列)DataFrame
设置索引df.set_index('col')指定某列作为新索引DataFrame
  1. loc** vs **iloc
    ○ loc:基于标签(index/column names),切片为闭区间(如df.loc[‘a’:‘c’]包含’c’)。
    ○ iloc:基于整数位置(从0开始),切片为左闭右开(如df.iloc[0:2]不包含索引2)。

  2. 布尔条件筛选
    ○ 支持组合条件(需用&、|,并用括号分隔条件):

Python
df[(df['col1'] > 3) & (df['col2'] == 'A')]
  1. at**/iat vs loc/**iloc
    ○ at/iat:仅用于访问单个值,速度更快。
    ○ loc/iloc:支持多行/列选择,功能更灵活。

获取一列数据

Python

# 访问数据
print(df['name'])  #访问某列数据
print(df.score)
 # df["col"] / df.col
df["name"]       # 返回 Series
df.name      
df[["name"]]     # 返回 DataFrame

获取多列数据

Python
df[["date", "temp_max", "temp_min"]]  # 获取多列数据
print(df[['name','score']]) # 访问多列数据

获取行数据loc:通过行标签获取数据

Python
df.loc[1]  # 获取行标签为1的数据
df.loc[[1, 10, 100]]  # 获取行标签分别为1、10、100的数据

iloc:通过行位置获取数据

Python
df.iloc[0]  # 获取行位置为0的数据
df.iloc[-1]  # 获取行位置为最后一位的数据

获取指定单元格

Python
df.loc[101, "name"]    # 标签访问
df.iloc[0, 1]          # 位置访问
df.loc[1, "precipitation"]  # 获取行标签为1,列标签为precipitation的数据
df.loc[:, "precipitation"]  # 获取所有行,列标签为precipitation的数据
df.iloc[:, [3, 5, -1]]  # 获取所有行,列位置为3,5,最后一位的数据
df.iloc[:10, 2:6]  # 获取前10行,列位置为2、3、4、5的数据
df.loc[:10, ["date", "precipitation", "temp_max", "temp_min"]]  # 通过行列标签获取数据

查看部分数据
通过head()、tail()获取前n行或后n行

Python
print(df.head())
print(df.tail(10))

使用布尔索引筛选数据

Python
# 条件筛选
df['score']>70
print(df[df.score>70])
print(df[(df['score']>70) & (df['age']<20)])
# 随机抽样
df.sample(2)

3.2 常用方法与统计

方法说明
数据查看
head(n=5)查看前n行数据(默认5行)
tail(n=5)查看后n行数据(默认5行)
条件筛选
isin(values)判断元素是否包含在参数集合中
isna()检测元素是否为缺失值(等价于isnull()
统计计算
sum()求和(默认按列计算,axis=1按行)
mean()计算平均值
min()/max()返回最小值/最大值
var(ddof=1)计算方差(默认样本方差,ddof=0为总体方差)
std(ddof=1)计算标准差
median()返回中位数
mode()返回众数(可能有多个)
quantile(q=0.5)返回指定分位数(如q=0.5为中位数)
数据描述
describe()返回数值列的统计信息(计数、均值、标准差、最小值、四分位数等)
info()显示DataFrame的基本信息(列名、非空计数、数据类型等)
值计数与去重
value_counts()统计每个唯一值的出现次数(normalize=True返回比例)
count()返回非空元素数量
drop_duplicates()去重(keep='first'保留首次出现,keep=False删除所有重复)
抽样与替换
sample(n)随机抽取n行数据
replace(old, new)替换指定值(支持字典映射或正则表达式)
比较与累计计算
equals(df)判断两个DataFrame是否完全相同
cummax()/cummin()计算累计最大值/最小值
cumsum()/cumprod()计算累计和/累计积
差分与排序
diff(periods=1)计算一阶差分(periods控制步长,正数向前,负数向后)
sort_index()按行或列索引排序(axis=0按行索引,axis=1按列名)
sort_values(by)按指定列值排序(ascending=False降序,支持多列排序)
nlargest(n, cols)返回某列最大的n条数据(等价于sort_values(ascending=False).head(n)
nsmallest(n, cols)返回某列最小的n条数据
Python
import pandas as pd
df = pd.DataFrame(data={"id": [101, 102, 103,104,105,106,101], "name": ["张三", "李四", "王五","赵六","冯七","周八","张三"], "age": [10, 20, 30, 40, None, 60,10]},index=["aa", "bb", "cc", "dd", "ee", "ff","aa"])
# head()    查看前n行数据,默认5行
print(df.head())
# tail()    查看后n行数据,默认5行
print(df.tail())
# isin()    元素是否包含在参数集合中
print(df.isin([103,106]))
# isna()    元素是否为缺失值
print(df.isna())
# sum() 求和
print(df["age"].sum())
# mean()    平均值
print(df["age"].mean())
# min() 最小值
print(df["age"].min())
# max() 最大值
print(df["age"].max())
# var() 方差
print(df["age"].var())
# std() 标准差
print(df["age"].std())
# median()  中位数
print(df["age"].median())
# mode()    众数
print(df["age"].mode())
# quantile()    指定位置的分位数,如quantile(0.5)
print(df["age"].quantile(0.5))
# describe()    常见统计信息
print(df.describe())
# info()    基本信息
print(df.info())
# value_counts()    每个元素的个数
print(df.value_counts())
# count()   非空元素的个数
print(df.count())
# drop_duplicates() 去重  duplicated()判断是否为重复行
print(df.duplicated(subset="age"))
# sample()  随机采样
print(df.sample())
# replace() 用指定值代替原有值
print("----------------")
print(df.replace(20,"haha"))

# cummax()  累计最大值
df3 = pd.DataFrame({'A': [2, 5, 3, 7, 4],'B': [1, 6, 2, 8, 3]})
# 按列  等价于axis=0 默认
print(df3.cummax(axis="index"))
# 按行  等价于axis=1
print(df3.cummax(axis="columns"))
# cummin()  累计最小值
print(df3.cummin())
# cumsum()  累计和
print(df3.cumsum())
# cumprod() 累计积
print(df3.cumprod())
# diff()    一阶差分
print(df3.diff())
# sort_index()  按行索引排序
print(df.sort_index())
# sort_values() 按某列的值排序,可传入列表来按多列排序,并通过ascending参数设置升序或降序
print(df.sort_values(by="age"))
# nlargest()    返回某列最大的n条数据
print(df.nlargest(n=2,columns="age"))
# nsmallest()   返回某列最小的n条数据
print(df.nsmallest(n=1,columns="age"))

在Pandas的 DataFrame 方法里,axis 是一个非常重要的参数,它用于指定操作的方向。
axis 参数可以取两个主要的值,即 0 或 ‘index’,以及 1 或 ‘columns’ ,其含义如下:
• axis=0 或 axis=‘index’:表示操作沿着行的方向进行,也就是对每一列的数据进行处理。例如,当计算每列的均值时,就是对每列中的所有行数据进行计算。
• axis=1 或 axis=‘columns’:表示操作沿着列的方向进行,也就是对每行的数据进行处理。例如,当计算每行的总和时,就是对每行中的所有列数据进行计算。

3.3 运算

标量运算
标量与每个元素进行计算。

Python
df = pd.DataFrame(data={"age": [20, 30, 40, 10], "name": ["张三", "李四", "王五", "赵六"]},
    columns=["name", "age"],
    index=[101, 104, 103, 102],
)
print(df * 2)
#      name  age
# 101  张三张三   40
# 104  李四李四   60
# 103  王五王五   80
# 102  赵六赵六   20

df1 = pd.DataFrame(
    data={"age": [10, 20, 30, 40], "name": ["张三", "李四", "王五", "赵六"]},
    columns=["name", "age"],
    index=[101, 102, 103, 104],
)
df2 = pd.DataFrame(
    data={"age": [10, 20, 30, 40], "name": ["张三", "李四", "王五", "田七"]},
    columns=["name", "age"],
    index=[102, 103, 104, 105],
)
print(df1 + df2)
#      name   age
# 101   NaN   NaN
# 102  李四张三  30.0
# 103  王五李四  50.0
# 104  赵六王五  70.0
# 105   NaN   NaN

3.4 案例练习

案例1:学生成绩分析

场景:某班级的学生成绩数据如下,请完成以下任务:

  1. 计算每位学生的总分和平均分。
  2. 找出数学成绩高于90分或英语成绩高于85分的学生。
  3. 按总分从高到低排序,并输出前3名学生。
Python
import pandas as pd

data = {
    '姓名': ['张三', '李四', '王五', '赵六', '钱七'],
    '数学': [85, 92, 78, 88, 95],
    '英语': [90, 88, 85, 92, 80],
    '物理': [75, 80, 88, 85, 90]
}
df = pd.DataFrame(data)

# 1. 计算总分和平均分
df['总分'] = df[['数学', '英语', '物理']].sum(axis=1)
df['平均分'] = df['总分'] / 3

# 2. 找出数学>90或英语>85的学生
high_scores = df[(df['数学'] > 90) | (df['英语'] > 85)]

# 3. 按总分排序并输出前3名
top3 = df.sort_values('总分', ascending=False).head(3)

print("总分和平均分:\n", df)
print("\n数学>90或英语>85的学生:\n", high_scores)
print("\n总分前3名学生:\n", top3)

案例2:销售数据分析

场景:某公司销售数据如下,请完成以下任务:

  1. 计算每种产品的总销售额(销售额 = 单价 × 销量)。
  2. 找出销售额最高的产品。
  3. 按销售额从高到低排序,并输出所有产品信息。
Python
import pandas as pd

data = {
    '产品名称': ['A', 'B', 'C', 'D'],
    '单价': [100, 150, 200, 120],
    '销量': [50, 30, 20, 40]
}
df = pd.DataFrame(data)

# 1. 计算总销售额
df['销售额'] = df['单价'] * df['销量']

# 2. 找出销售额最高的产品
max_sales = df[df['销售额'] == df['销售额'].max()]

# 3. 按销售额排序
sorted_df = df.sort_values('销售额', ascending=False)

print("销售额计算:\n", df)
print("\n销售额最高的产品:\n", max_sales)
print("\n按销售额排序:\n", sorted_df)

案例3:员工考勤统计

场景:某部门员工考勤数据如下,请完成以下任务:

  1. 计算每位员工的出勤率(出勤率 = 出勤天数 / 工作日总数)。
  2. 标记出勤率低于80%的员工。
  3. 按出勤率从高到低排序。
Python
import pandas as pd

data = {
    '姓名': ['张三', '李四', '王五', '赵六'],
    '出勤天数': [20, 15, 18, 22],
    '工作日总数': [25, 20, 25, 25]
}
df = pd.DataFrame(data)

# 1. 计算出勤率
df['出勤率'] = (df['出勤天数'] / df['工作日总数']).round(2)

# 2. 标记出勤率<80%的员工
df['需关注'] = df['出勤率'] < 0.8

# 3. 按出勤率排序
sorted_df = df.sort_values('出勤率', ascending=False)

print("出勤率统计:\n", df)
print("\n出勤率排序:\n", sorted_df)

案例4:电影评分分析

场景:某电影评分数据如下,请完成以下任务:

  1. 计算每部电影的平均评分。
  2. 找出评分高于8.5的电影。
  3. 按平均评分从高到低排序。
Python
import pandas as pd

data = {
    '电影名称': ['电影A', '电影B', '电影C', '电影D'],
    '评分1': [9.0, 8.5, 8.0, 7.5],
    '评分2': [8.5, 9.0, 8.5, 8.0],
    '评分3': [9.5, 8.0, 7.5, 7.0]
}
df = pd.DataFrame(data)

# 1. 计算平均评分
df['平均评分'] = df[['评分1', '评分2', '评分3']].mean(axis=1).round(2)

# 2. 找出评分>8.5的电影
high_rated = df[df['平均评分'] > 8.5]

# 3. 按平均评分排序
sorted_df = df.sort_values('平均评分', ascending=False)

print("平均评分:\n", df)
print("\n评分>8.5的电影:\n", high_rated)
print("\n按评分排序:\n", sorted_df)

案例5:股票价格分析

场景:某股票价格数据如下,请完成以下任务:

  1. 计算每日股价的涨跌幅(涨跌幅 = (当日收盘价 - 前一日收盘价) / 前一日收盘价)。
  2. 找出涨幅超过5%的日期。
  3. 按日期排序,并输出涨跌幅最高的日期。
Python
import pandas as pd

data = {
    '日期': ['2023-01-01', '2023-01-02', '2023-01-03', '2023-01-04'],
    '收盘价': [100, 105, 110, 102]
}
df = pd.DataFrame(data)
df['日期'] = pd.to_datetime(df['日期'])

# 1. 计算涨跌幅
df['涨跌幅'] = df['收盘价'].pct_change().round(4)

# 2. 找出涨幅>5%的日期
high_increase = df[df['涨跌幅'] > 0.05]

# 3. 按日期排序并输出最高涨跌幅日期
sorted_df = df.sort_values('日期')
max_increase_date = df.loc[df['涨跌幅'].idxmax(), '日期']

print("涨跌幅计算:\n", df)
print("\n涨幅>5%的日期:\n", high_increase)
print("\n涨跌幅最高的日期:\n", max_increase_date)

案例6:电商用户行为分析(基础版)

场景:某电商平台的用户行为数据如下,请完成以下任务:

  1. 计算每位用户的总消费金额(消费金额 = 商品单价 × 购买数量)
  2. 找出消费金额最高的用户,并输出其所有信息
  3. 计算所有用户的平均消费金额(保留2位小数)
  4. 统计电子产品的总购买数量
Python
import pandas as pd

data = {
    '用户ID': [101, 102, 103, 104, 105],
    '用户名': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
    '商品类别': ['电子产品', '服饰', '电子产品', '家居', '服饰'],
    '商品单价': [1200, 300, 800, 150, 200],
    '购买数量': [1, 3, 2, 5, 4]
}
df = pd.DataFrame(data)

# 1. 计算总消费金额
df['消费金额'] = df['商品单价'] * df['购买数量']

# 2. 找出消费金额最高的用户
max_spend_user = df[df['消费金额'] == df['消费金额'].max()]

# 3. 计算平均消费金额
avg_spend = round(df['消费金额'].mean(), 2)

# 4. 统计电子产品的总购买数量
electronic_total = df[df['商品类别'] == '电子产品']['购买数量'].sum()

print("用户消费分析:\n", df)
print("\n消费金额最高的用户:\n", max_spend_user)
print("\n平均消费金额:", avg_spend)
print("电子产品总购买数量:", electronic_total)

输出示例:

Plain Text
用户消费分析:
    用户ID     用户名  商品类别  商品单价  购买数量  消费金额
0   101    Alice  电子产品   1200       1   1200
1   102      Bob     服饰    300       3    900
2   103  Charlie  电子产品    800       2   1600
3   104    David     家居    150       5    750
4   105      Eve     服饰    200       4    800

消费金额最高的用户:
    用户ID     用户名  商品类别  商品单价  购买数量  消费金额
2   103  Charlie  电子产品    800       2   1600

平均消费金额: 1050.0
电子产品总购买数量: 3

3.5 数据的导入与导出

导出数据

方法说明
to_csv()将数据保存为 CSV 格式文件,数据之间以逗号分隔。可通过 sep 参数设置其他分隔符,通过 index 参数设置是否保存行标签,通过 header 参数设置是否保存列标签。
to_pickle()若要保存计算的中间结果或需在 Python 中复用的对象,可保存为 .pickle 文件。此格式仅能在 Python 中使用,扩展名可为 .p.pkl.pickle
to_excel()保存为 Excel 文件,需安装 openpyxl 包。
to_clipboard()将数据保存到剪切板。
to_dict()保存为字典格式。
to_hdf()保存为 HDF 格式文件,需安装 tables 包。
to_html()保存为 HTML 格式,需安装 lxmlhtml5libbeautifulsoup4 包。
to_json()保存为 JSON 格式。
to_feather()保存为 Feather 二进制格式文件。该格式可在 Python 与 R 之间高效读写,速度快于 CSV。通常用于中间数据传递而非最终数据保存。需安装 pyarrow 包。
to_sql()将数据保存到数据库中。
Python
import os
import pandas as pd

os.makedirs("data", exist_ok=True)
df = pd.DataFrame({"age": [20, 30, 40, 10], "name": ["张三", "李四", "王五", "赵六"], "id": [101, 102, 103, 104]})
df.set_index("id", inplace=True)

df.to_csv("data/df.csv")
df.to_csv("data/df.tsv", sep="\t")  # 设置分隔符为 \t
df.to_csv("data/df_noindex.csv", index=False)  # index=False 不保存行索引
df.to_pickle("data/df.pkl")
df.to_excel("data/df.xlsx")
df.to_clipboard()
df_dict = df.to_dict()
df.to_hdf("data/df.h5", key="df")
df.to_html("data/df.html")
df.to_json("data/df.json")
df.to_feather("data/df.feather")

导入数据

方法说明
read_csv()加载 CSV 格式的数据。可通过 sep 参数指定分隔符,可通过 index_col 参数指定行索引。
read_pickle()加载 Pickle 格式的数据。
read_excel()加载 Excel 格式的数据。
read_clipboard()加载剪切板中的数据。
read_hdf()加载 HDF 格式的数据。
read_html()加载 HTML 格式的数据。
read_json()加载 JSON 格式的数据。
read_feather()加载 Feather 格式的数据。
read_sql()加载数据库中的数据。
Python
df_csv = pd.read_csv("data/df.csv", index_col="id")  # 指定行索引
df_tsv = pd.read_csv("data/df.tsv", sep="\t")  # 指定分隔符
df_pkl = pd.read_pickle("data/df.pkl")
df_excel = pd.read_excel("data/df.xlsx", index_col="id")
df_clipboard = pd.read_clipboard(index_col="id")
df_from_dict = pd.DataFrame(df_dict)
df_hdf = pd.read_hdf("data/df.h5", key="df")
df_html = pd.read_html("data/df.html", index_col=0)[0]
df_json = pd.read_json("data/df.json")
df_feather = pd.read_feather("data/df.feather")

print(df_csv)
print(df_tsv)
print(df_pkl)
print(df_excel)
print(df_clipboard)
print(df_from_dict)
print(df_hdf)
print(df_html)
print(df_json)
print(df_feather)

当json数据比较复杂时,可以先用json库导入,再导入DataFrame

import json
with open('data/test.json') as f:
    data = json.load(f)
print(data)
print(type(data))
df = pd.DataFrame(data['users'])

3.6 数据清洗与预处理

章节核心内容关键知识点
1. 缺失值处理检测、删除和填充缺失值的方法isna(), dropna(), fillna(), 前向/后向填充, 均值/中位数填充
2. 重复数据处理识别和删除重复行duplicated(), drop_duplicates(), 按列去重, 保留首次/最后一次出现
3. 数据类型转换强制类型转换、日期/分类数据处理astype(), to_datetime(), 分类数据优化, 数值格式化
4. 数据重塑与变形行列转置、宽表长表转换、分列操作T 转置, melt(), pivot(), str.split() 分列
5. 文本数据处理字符串清洗、正则提取、大小写转换str.lower(), str.replace(), str.extract(), 空格处理
6. 数据分箱与离散化数值分箱(等宽/等频)pd.cut(), pd.qcut(), 离散化应用场景
7. 其他常用转换重命名列、索引操作、函数应用、内存优化rename(), set_index(), apply(), 类型优化减少内存占用

1. 缺失值处理

方法/操作语法示例描述
检测缺失值df.isna()df.isnull()返回布尔矩阵,标记缺失值(NaNNone
统计缺失值df.isna().sum()统计每列缺失值数量
删除缺失值(行)df.dropna()删除包含缺失值的行(默认)
删除缺失值(列)df.dropna(axis=1)删除包含缺失值的列
删除指定列的缺失值行df.dropna(subset=['col1'])仅删除指定列中存在缺失值的行
填充缺失值(固定值)df.fillna(value)用固定值填充(例如:df.fillna(0)
前向填充df.fillna(method='ffill')用前一个非缺失值填充(向前填充)
后向填充df.fillna(method='bfill')用后一个非缺失值填充(向后填充)
均值填充df.fillna(df.mean())用各列的均值填充缺失值

pandas中的缺失值
• NaN (Not a Number) 是缺失值的标志
• 方法: isna(), notna()
pandas使用浮点值NaN(Not a Number)表示缺失数据,使用NA(Not Available)表示缺失值。可以通过isnull()、isna()或notnull()、notna()方法判断某个值是否为缺失值。
Nan通常表示一个无效的或未定义的数字值,是浮点数的一种特殊取值,用于表示那些不能表示为正常数字的情况,如 0/0、∞-∞等数学运算的结果。nan与任何值(包括它自身)进行比较的结果都为False。例如在 Python 中,nan == nan返回False。
NA一般用于表示数据不可用或缺失的情况,它的含义更侧重于数据在某种上下文中是缺失或不存在的,不一定特指数字类型的缺失。
na和nan都用于表示缺失值,但nan更强调是数值计算中的特殊值,而na更强调数据的可用性或存在性。

判断缺失值

Python
s = pd.Series([np.nan, None, pd.NA])
print(s)
# 0     NaN
# 1    None
# 2    <NA>
# dtype: object
print(s.isnull())
# 0    True
# 1    True
# 2    True
# dtype: bool

加载数据中包含缺失值

Python
df = pd.read_csv("data/weather_withna.csv")
print(df.tail(5))
#             date  precipitation  temp_max  temp_min  wind weather
# 1456  2015-12-27            NaN       NaN       NaN   NaN     NaN
# 1457  2015-12-28            NaN       NaN       NaN   NaN     NaN
# 1458  2015-12-29            NaN       NaN       NaN   NaN     NaN
# 1459  2015-12-30            NaN       NaN       NaN   NaN     NaN
# 1460  2015-12-31           20.6      12.2       5.0   3.8    rain

可以通过keep_default_na参数设置是否将空白值设置为缺失值。

Python
df = pd.read_csv("data/weather_withna.csv", keep_default_na=False)
print(df.tail(5))
#             date precipitation temp_max temp_min wind weather
# 1456  2015-12-27
# 1457  2015-12-28
# 1458  2015-12-29
# 1459  2015-12-30
# 1460  2015-12-31          20.6     12.2      5.0  3.8    rain

可通过na_values参数将指定值设置为缺失值。

Python
df = pd.read_csv("data/weather_withna.csv", na_values=["2015-12-31"])
print(df.tail(5))
#             date  precipitation  temp_max  temp_min  wind weather
# 1456  2015-12-27            NaN       NaN       NaN   NaN     NaN
# 1457  2015-12-28            NaN       NaN       NaN   NaN     NaN
# 1458  2015-12-29            NaN       NaN       NaN   NaN     NaN
# 1459  2015-12-30            NaN       NaN       NaN   NaN     NaN
# 1460         NaN           20.6      12.2       5.0   3.8    rain

查看缺失值
通过isnull()查看缺失值数量

Python
df = pd.read_csv("data/weather_withna.csv")
print(df.isnull().sum())
# date               0
# precipitation    303
# temp_max         303
# temp_min         303
# wind             303
# weather          303
# dtype: int64

剔除缺失值
通过dropna()方法来剔除缺失值。
Series剔除缺失值

Python
s = pd.Series([1, pd.NA, None])
print(s)
# 0       1
# 1    <NA>
# 2    None
# dtype: object
print(s.dropna())
# 0    1
# dtype: object

DataFrame剔除缺失值
无法从DataFrame中单独剔除一个值,只能剔除缺失值所在的整行或整列。默认情况下,dropna()会剔除任何包含缺失值的整行数据。

Python
df = pd.DataFrame([[1, pd.NA, 2], [2, 3, 5], [pd.NA, 4, 6]])
print(df)
#       0     1  2
# 0     1  <NA>  2
# 1     2     3  5
# 2  <NA>     4  6
print(df.dropna())
#    0  1  2
# 1  2  3  5

可以设置按不同的坐标轴剔除缺失值,比如axis=1(或 axis=‘columns’)会剔除任何包含缺失值的整列数据。

df = pd.DataFrame([[1, pd.NA, 2], [2, 3, 5], [pd.NA, 4, 6]])
print(df)
#       0     1  2
# 0     1  <NA>  2
# 1     2     3  5
# 2  <NA>     4  6
print(df.dropna(axis=1))
#    2
# 0  2
# 1  5
# 2  6

有时只需要剔除全部是缺失值的行或列,或者绝大多数是缺失值的行或列。这些需求可以通过设置how或thresh参数来满足,它们可以设置剔除行或列缺失值的数量阈值。

df = pd.DataFrame([[1, pd.NA, 2], [pd.NA, pd.NA, 5], [pd.NA, pd.NA, pd.NA]])
print(df)
#       0     1     2
# 0     1  <NA>     2
# 1  <NA>  <NA>     5
# 2  <NA>  <NA>  <NA>
print(df.dropna(how="all"))  # 如果所有值都是缺失值,则删除这一行
#       0     1  2
# 0     1  <NA>  2
# 1  <NA>  <NA>  5
print(df.dropna(thresh=2))  # 如果至少有2个值不是缺失值,则保留这一行
#    0     1  2
# 0  1  <NA>  2

可以通过设置subset参数来设置某一列有缺失值则进行剔除。

df = pd.DataFrame([[1, pd.NA, 2], [pd.NA, pd.NA, 5], [pd.NA, pd.NA, pd.NA]])
print(df)
#       0     1     2
# 0     1  <NA>     2
# 1  <NA>  <NA>     5
# 2  <NA>  <NA>  <NA>
print(df.dropna(subset=[0]))  # 如果0列有缺失值,则删除这一行
#    0     1  2
# 0  1  <NA>  2

填充缺失值
使用固定值填充
通过fillna()方法,传入值或字典进行填充。

df = pd.read_csv("data/weather_withna.csv")
print(df.fillna(0).tail())  # 使用固定值填充
#   
print(df.fillna({"temp_max": 60, "temp_min": -60}).tail())  # 使用字典来填充
#             date  precipitation  temp_max  temp_min  wind weather
# 1456  2015-12-27            NaN      60.0     -60.0   NaN     NaN
# 1457  2015-12-28            NaN      60.0     -60.0   NaN     NaN
# 1458  2015-12-29            NaN      60.0     -60.0   NaN     NaN
# 1459  2015-12-30            NaN      60.0     -60.0   NaN     NaN
# 1460  2015-12-31           20.6      12.2       5.0   3.8    rain

使用统计值填充
通过fillna()方法,传入统计后的值进行填充。

print(df.fillna(df[["precipitation", "temp_max", "temp_min", "wind"]].mean()).tail())  # 使用平均值填充
#             date  precipitation   temp_max  temp_min      wind weather
# 1456  2015-12-27       3.052332  15.851468  7.877202  3.242055     NaN
# 1457  2015-12-28       3.052332  15.851468  7.877202  3.242055     NaN
# 1458  2015-12-29       3.052332  15.851468  7.877202  3.242055     NaN
# 1459  2015-12-30       3.052332  15.851468  7.877202  3.242055     NaN
# 1460  2015-12-31      20.600000  12.200000  5.000000  3.800000    rain

使用前后的有效值填充
通过ffill()或bfill()方法使用前面或后面的有效值填充。

print(df.ffill().tail())  # 使用前面的有效值填充
#             date  precipitation  temp_max  temp_min  wind weather
# 1456  2015-12-27            0.0      11.1       4.4   4.8     sun
# 1457  2015-12-28            0.0      11.1       4.4   4.8     sun
# 1458  2015-12-29            0.0      11.1       4.4   4.8     sun
# 1459  2015-12-30            0.0      11.1       4.4   4.8     sun
# 1460  2015-12-31           20.6      12.2       5.0   3.8    rain
print(df.bfill().tail())  # 使用后面的有效值填充
#             date  precipitation  temp_max  temp_min  wind weather
# 1456  2015-12-27           20.6      12.2       5.0   3.8    rain
# 1457  2015-12-28           20.6      12.2       5.0   3.8    rain
# 1458  2015-12-29           20.6      12.2       5.0   3.8    rain
# 1459  2015-12-30           20.6      12.2       5.0   3.8    rain
# 1460  2015-12-31           20.6      12.2       5.0   3.8    rain

通过线性插值填充
通过interpolate()方法进行线性插值填充。线性插值操作,就是用于在已知数据点之间估算未知数据点的值。interpolate 方法支持多种插值方法,可通过 method 参数指定,常见的方法有:
• ‘linear’:线性插值,基于两点之间的直线来估算缺失值,适用于数据呈线性变化的情况。
• ‘time’:适用于时间序列数据,会考虑时间间隔进行插值。
• ‘polynomial’:多项式插值,通过拟合多项式曲线来估算缺失值,可通过 order 参数指定多项式的阶数。

# 创建包含缺失值的 Series
s = pd.Series([1, np.nan, 3, 4, np.nan, 6])
# 使用默认的线性插值方法填充缺失值
s_interpolated = s.interpolate()
print(s_interpolated)

# 0    1.0
# 1    2.0
# 2    3.0
# 3    4.0
# 4    5.0
# 5    6.0
# dtype: float64

总结

Python
# 缺失值
import numpy as np
# 缺失值的类型 nan na
s = pd.Series([np.nan, None, pd.NA,2,4])
df = pd.DataFrame([[1, pd.NA, 2], [2, 3, 5], [pd.NA, 4, 6]])
print(s)
print(s.isnull())  #查看是否是缺失值
print(s.isna()) #查看是否是缺失值
print(s.isna().sum()) # 缺失值的个数
# 剔除缺失值
print(s.dropna())  #series剔除缺失值
print(df.dropna()) #只要有缺失值,就剔除一整条记录
print(df.dropna(how="all")) # 如果所有值都是缺失值,则删除这一行
print(df.dropna(thresh=2)) # 如果至少有2个值不是缺失值,则保留这一行
print(df.dropna(axis=1))  #剔除一列中含缺失值的列
#可以通过设置subset参数来设置某一列有缺失值则进行剔除。
print(df.dropna(subset=[0]))# 如果0列有缺失值,则删除这一行
#填充缺失值
print('********')
df = pd.read_csv("data/weather_withna.csv")
# df = df.fillna({"temp_max": 60, "temp_min": -60}) # 使用字典来填充
print(df['temp_max'].mean())
df.fillna(df[["precipitation", "temp_max", "temp_min", "wind"]].mean()).tail() # 使用平均值填充
print(df.ffill().tail()) # 使用前面的有效值填充
print(df.bfill().tail()) # 使用后面的有效值填充

df1 = pd.read_csv("data/weather_withna.csv")
df2 = pd.read_csv("data/weather_withna.csv", keep_default_na=False)
print(df1.temp_max.count())
print(df1.isnull().sum())
print(df2.temp_max.count())
print(df2.isnull().sum())
# 将
df = pd.read_csv("data/weather_withna.csv", na_values=["2015-12-31"])
# print(df.tail(5))
print(df.isnull().sum())

2.重复数据处理

方法/操作语法示例描述
检测重复行df.duplicated()返回布尔序列,标记重复行(首次出现的行标记为 False
删除重复行(默认)df.drop_duplicates()删除重复行,保留首次出现的行(默认检查所有列)
根据指定列去重df.drop_duplicates(subset=['col1'])仅根据指定列判断并删除重复行
保留最后一次出现的行df.drop_duplicates(keep='last')删除重复行,仅保留最后一次出现的记录

1. 检测重复行

Python
import pandas as pd

# 创建包含重复数据的DataFrame
data = {
    'Name': ['Alice', 'Bob', 'Alice', 'Charlie', 'Bob'],
    'Age': [25, 30, 25, 35, 30],
    'City': ['NY', 'LA', 'NY', 'SF', 'LA']
}
df = pd.DataFrame(data)

# 检测重复行(默认检查所有列)
print("重复行标记(False表示首次出现,True表示重复):")
print(df.duplicated())

输出:

Plain Text
0    False
1    False
2     True
3    False
4     True
dtype: bool

2. 删除重复行

Python
# 默认保留首次出现的行
df_unique = df.drop_duplicates()
print("去重后的DataFrame:")
print(df_unique)

输出:

Plain Text
      Name  Age City
0    Alice   25   NY
1      Bob   30   LA
3  Charlie   35   SF

3. 按指定列去重

Python
# 仅根据'Name'列去重(保留首次出现)
df_name_unique = df.drop_duplicates(subset=['Name'])
print("按Name列去重:")
print(df_name_unique)

输出:

Plain Text
      Name  Age City
0    Alice   25   NY
1      Bob   30   LA
3  Charlie   35   SF

4. 保留最后一次出现的重复行

Python
# 保留最后一次出现的行
df_last = df.drop_duplicates(keep='last')
print("保留最后一次出现的行:")
print(df_last)

输出:

Plain Text
      Name  Age City
2    Alice   25   NY
4      Bob   30   LA
3  Charlie   35   SF

5. 综合案例:处理真实数据

Python
# 加载包含重复值的数据(示例)
df_sales = pd.read_csv("sales_data.csv")

# 检查重复行数量
print("原始数据重复行数:", df_sales.duplicated().sum())

# 按'Order_ID'列去重,保留最后一次记录
df_clean = df_sales.drop_duplicates(subset=['Order_ID'], keep='last')

# 验证结果
print("去重后数据行数:", len(df_clean))

注意事项

  1. 性能优化:对大数据集去重时,可通过 subset 指定关键列以减少计算量。
  2. 逻辑一致性:确保 keep=‘last’ 或 keep=False(删除所有重复)符合业务需求。
  3. 多列去重:subset=[‘col1’, ‘col2’] 可联合多列判断重复。

通过以上案例,可以灵活应对实际数据清洗中的重复值问题!

3. 数据类型转换

方法/操作语法示例描述
查看数据类型df.dtypes显示每列的数据类型
强制类型转换df['col'].astype('int')将列转换为指定类型(如 intfloatstrdatetime
转换为日期时间pd.to_datetime(df['col'])将字符串列转换为 datetime 类型
转换为分类数据df['col'].astype('category')将列转换为分类类型(节省内存,提高性能)
数值格式化df['col'].round(2)对数值保留 2 位小数

核心方法

操作方法/函数描述
查看数据类型df.dtypes显示每列的数据类型(如 int64float64object 等)。
强制类型转换df['col'].astype('type')将列转换为指定类型(如 intfloatstrbool 等)。
转换为日期时间pd.to_datetime(df['col'])将字符串或数值列转换为 datetime 类型(支持自定义格式)。
转换为分类数据df['col'].astype('category')将列转换为分类类型(节省内存,提高性能,适用于有限取值的列,如性别、省份等)。
数值格式化df['col'].round(2)保留指定小数位数(如 2 位)。

1. 查看数据类型

Python
import pandas as pd

# 加载数据(以sleep.csv为例)
df = pd.read_csv("sleep.csv")
print(df.dtypes)

输出示例:

Plain Text
person_id                     int64
gender                       object
age                           int64
occupation                   object
sleep_duration              float64
sleep_quality               float64
...                          ...

说明:object通常为字符串或混合类型,需检查是否需要转换。

2. 强制类型转换
将数值列转换为整数或字符串:

Python
# 将sleep_duration从float转为int(丢失小数部分)
df['sleep_duration_int'] = df['sleep_duration'].astype('int32')

# 将gender转为字符串
df['gender_str'] = df['gender'].astype('str')

print(df[['sleep_duration', 'sleep_duration_int', 'gender_str']].head())

输出:

Plain Text
   sleep_duration  sleep_duration_int gender_str
0             7.4                  7       Male
1             4.2                  4     Female
2             6.1                  6       Male

3. 转换为分类数据
优化内存和性能(适用于低基数列):

Python
# 将gender列转为分类类型
df['gender'] = df['gender'].astype('category')
print(df['gender'].dtypes)

输出:

Plain Text
category

优势:
• 减少内存占用(尤其对重复值多的列)。
• 加速groupby、sort等操作。

4. 数值格式化
控制小数位数:

Python
# 保留sleep_quality的2位小数
df['sleep_quality_rounded'] = df['sleep_quality'].round(2)
print(df[['sleep_quality', 'sleep_quality_rounded']].head())

输出:

Plain Text
   sleep_quality  sleep_quality_rounded
0            7.0                   7.00
1            4.9                   4.90
2            6.0                   6.00

常见问题与技巧

  • 处理转换错误:使用errors='coerce’将无效值转为NaN,避免报错:
Python
df['age'] = pd.to_numeric(df['age'], errors='coerce')

  • 处理转换错误:使用errors='coerce’将无效值转为NaN,避免报错:
Python
df['age'] = df['age'].astype('int32')

  • 布尔类型转换:将字符串(如"Yes"/“No”)转为布尔值:
Python
df['is_active'] = df['active_flag'].map({'Yes': True, 'No': False})

  • 自定义格式化:使用apply实现复杂转换(如百分比):
Python
df['score_percent'] = df['score'].apply(lambda x: f"{x*100:.1f}%")

实战案例:处理penguins.csv

Python
df_penguins = pd.read_csv("penguins.csv")

# 1. 转换sex为分类类型
df_penguins['sex'] = df_penguins['sex'].astype('category')

# 2. 补全缺失值后转换bill_length_mm为float32
df_penguins['bill_length_mm'] = df_penguins['bill_length_mm'].fillna(0).astype('float32')

# 3. 检查并输出结果
print(df_penguins[['species', 'sex', 'bill_length_mm']].dtypes)

输出:

Plain Text
species           object
sex             category
bill_length_mm    float32

4. 数据重塑与变形

方法/操作语法示例描述
行列转置df.T转置 DataFrame(行变列,列变行)
宽表转长表pd.melt(df, id_vars=['id'])将多列合并为键值对形式(生成 variablevalue 两列)
长表转宽表df.pivot(index='id', columns='var', values='val')将长表转换为宽表(类似 Excel 数据透视表操作)
分列操作df['col'].str.split(',', expand=True)按分隔符拆分字符串为多个列
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐