python模块 pands-操作excel
1、安装pandas
#更新pip python -m pip install "pandas==1.1.5" -i https://mirrors.aliyun.com/pypi/simple/ #安装pandas python -m pip remove "pandas==1.1.5" -i https://mirrors.aliyun.com/pypi/simple/

2、基础概念
2.1、pandas两个核心对象
- pandas里最核心的两个对象:Series和DataFrame
- Series是“一列数据”。
- 可以理解成:带标签的一维数组。
- 结构:索引(index)+值(values)
- 类似:Excel里的某一列
- DataFrame是“表格数据”
- 可以理解成:由多列Series组成的二维表
- 结构:行索引(index)+列名(columns)+每个单元格的值
- 类似:Excel表格、SQL数据表
- 两者关系:
- DataFrame的每一列,实际上就是一个Series
- 所以可以把DataFrame看成“多个Series按列排成的一张表”


2.2、Pandas支持的数据类型
- 具体类型是Python、Numpy各种类型的混合:
- float
- int
- string
- bool
- datetime64[nsr]、datetime64[nsr,tz]、timedelta[ns]
- category
- object
#在不同数据类型间转换
df.astype(
dtyp #指定转换的数据类型,可以使用numpy或者python中的数据类型:int/float/bool/str
copy=True #是否生成新的副本,而不是替换原数据框
errors="raise" #转换出错时是否抛出错误,raise/ignore
)
示例
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 查看各列的数据类型
df1.dtypes
# 将df里所有的列转换成str
df1.astype('str')
# 修改某一列数据的数据类型
df1['语文'].astype('str')
# 转换错误。忽略异常
df1['语文'].astype('int', errors='ignore')
3、Series对象
1、创建Series对象
import pandas as pd
# 创建Series对象,使用列表
data1 = pd.Series([1, 2, 3, 4])
# 创建Series对象,使用字典,默认将字典的key作为索引
stu = {"name": "张三", "age": 23, "sex": "男"}
data2 = pd.Series(stu)
# 创建Series对象,使用标量
data3 = pd.Series(20, index=list("abcd"))
>>>print(data1)
0 1
1 2
2 3
3 4
dtype: int64
>>>print(data2)
name 张三
age 23
sex 男
dtype: object
>>>print(data3)
a 20
b 20
c 20
d 20
dtype: int64
# 创建Series对象,使用列表,指定索引
data1_1 = pd.Series([1, 2, 3, 4], index=["a", "b", "c", "d"])
# 创建Series对象,使用列表,使用list指定索引
data1_2 = pd.Series([1, 2, 3, 4], index=list("abcd"))
>>>print(data1_1)
>>>print(data1_2)
a 1
b 2
c 3
d 4
dtype: int64
# 创建Series对象,使用字典,指定的索引,取交集
data2_1 = pd.Series(stu, index=["name", "sex"])
# 创建Series对象,使用字典,指定的索引,如果字典的key中不存在该索引,则改索引的值未Nan
data2_2 = pd.Series(stu, index=["name", "sex", "birth"])
>>>print(data2_1)
name 张三
sex 男
dtype: object
>>>print(data2_2)
name 张三
sex 男
birth NaN
dtype: object
2、查看Series对象
# 查看Series对象的索引 >>>print(data1.index) RangeIndex(start=0, stop=4, step=1) # 查看Series对象的值 >>>print(data1.values) [1 2 3 4]
4、DataFrame对象
1、创建DataFrame对象
import pandas as pd
# 创建两个字典
a_dict = {"bj": 11, "sh": 12, "gz": 13}
b_dict = {"bj": 21, "sh": 22, "gz": 23}
# 生成两个Series对象
a_series = pd.Series(a_dict)
b_series = pd.Series(b_dict)
# 创建dataFrame对象,使用两个Series对象。将Series对象作为字典的值传入DataFrame
data1 = pd.DataFrame({"a": a_series, "b": b_series})
# 创建dataFrame对象,使用一个Series对象。
data2 = pd.DataFrame(a_series)
# 创建dataFrame对象。使用列表,列表元素是字典
data3 = pd.DataFrame([a_dict, b_dict])
# 创建dataFrame对象,使用二维数组
import numpy as np
data4 = pd.DataFrame(np.random.randint(10, size=(3, 4)), index=list("abc"), columns=list("ABCD"))
>>>print(data1)
a b
bj 11 21
sh 12 22
gz 13 23
>>>print(data2)
0
bj 11
sh 12
gz 13
>>>print(data3)
bj sh gz
0 11 12 13
1 21 22 23
>>>print(data4)
A B C D
a 1 3 1 5
b 3 1 2 8
c 4 6 9 8
# 创建dataFrame对象,指定行索引和列索引
data3_1 = pd.DataFrame([a_dict, b_dict], index=["a", "b"])
data2_1 = pd.DataFrame(a_series, columns=["a"])
>>>print(data3_1)
bj sh gz
a 11 12 13
b 21 22 23
>>>print(data2_1)
a
bj 11
sh 12
gz 13
2、查看DataFrame对象
import pandas as pd # 获取dataFrame对象的index(行索引) print(data1.index) # 获取dataFrame对象的columes(列索引) print(data1.columns) # 获取dataFrame对象的values print(data1.values)
5、读取文件
5.1、读取excel文件
- 读Excel还需要额外库,一般是openpyxl(读.xlsx)或xlrd(老的.xls)
1、基本语法
df = pd.read_excel(
file_path,
sheet_name=0, # 要读取的第一张工作表(默认)。sheet_name="Sheet1",按名称。sheet_name=[0, 1],读多张表,返回 dict。sheet_name=None,读所有表,返回 dict
header=0, # 第0行作为列名。header=None使用整数作为列索引
index_col=0, # 用第0列做行索引。
usecols=None, # 只读哪些列。usecols=["姓名", "年龄"]
skiprows=None, # 跳过前几行(跳过表头上方无用行)
engine="openpyxl" # 指定用 openpyxl 引擎读取
)
2、读取excel文件
import pandas as pd
# 读取excel文件,默认第一个sheet
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 读取excel文件,指定sheet(sheet名称或sheet索引)
df2 = pd.read_excel("stu_data.xlsx", sheet_name="score",engine="openpyxl")
df3 = pd.read_excel("stu_data.xlsx", sheet_name=0, engine="openpyxl")
# 读取excel文件,所有sheet
df4 = pd.read_excel("stu_data.xlsx", sheet_name=None, engine="openpyxl")
# 读取excel文件,只读取指定的列
df5 = pd.read_excel("stu_data.xlsx", sheet_name=0, usecols=[0, 1, 2], engine="openpyxl")
df6 = pd.read_excel("stu_data.xlsx", sheet_name=0, usecols=["姓名", "性别", "语文"], engine="openpyxl")
# 设置显示的行数和列数
pd.options.display.max_rows = 3
pd.options.display.max_columns = 3
5.2、读取csv文件
- 需要设置编码格式,Python中用得比较多的两种编码格式是UTF-8和gbk,默认编码格式是UTF-8。
1、基本语法
df = pd.read_csv(
file_path,
encoding="utf-8", # 如果报错,换成 encoding="gbk"
sep="," # 指定分隔符,默认使用逗号
)
2、读取csv文件
import pandas as pd
#读取csv文件,指定文件编码格式utf-8
df1 = pd.read_csv("stu_data.csv",encoding="utf-8")
df2 = pd.read_csv("stu_data.csv",encoding="utf-8",sep=",")
5.3、读取txt文件
1、基本语法
df = pd.read_table(
file_path,
encoding="utf-8", # 中文可能用 encoding="gbk"
sep=",", # 指定分隔符,默认使用制表符\t
delim_whitespace=True # 自动用连续空白字符分隔(或 sep=r"\s+")
)
2、读取txt文件
import pandas as pd
# 读取txt文件。分隔符默认使用制表符\t
df1 = pd.read_table("stu_data.txt", encoding="utf-8", sep="\t")
5.4、读取mysql
- pandas读MySQL,一般是借助SQLAlchemy+数据库驱动,然后用pd.read_sql()或pd.read_sql_query()。
import pandas as pd
import pymysql
# 配置mysql连接引擎
conn = pymysql.connect(
host='localhost',
user='user',
passwd='passwd',
db='mydb',
port=3306,
charset='utf-8'
)
# 读取数据表(index_col,columns)
df = pd.read_sql(
sql='sql语句',
conn=conn,
index_col=None, # 被用做行索引的列名称
columns=None # 需要读取的列
)
6、保存数据
6.1、保存数据csv
df.to_csv(
file_path, # 保存路径
index=False, # 不保存行索引
encoding="utf-8", # 中文+Excel 推荐用 utf-8-sig
sep=",", # 指定分隔符,默认使用逗号
mode='w' # Python写模式,读写方式:r,r+,w,w+,a,a+
columns=[] # 需要导出的列,示例columns=['学号','性别','身高']
header=[] # 指定导出数据的列的新列名,可直接提供1ist。示例header=['sno','height','weight']
)
6.2、保存数据到Excel
# 保存一个DataFrame到Excel文件
df.to_excel(
file_path, # 保存路径
index=False, # 不把行索引写入 Excel
sheet_name="Sheet1" # 工作表名称
columns=[] # 需要导出的列,示例columns=['学号','性别','身高']
header=[] # 指定导出数据的列的新列名,可直接提供1ist。示例header=['sno','height','weight']
)
# 保存多个DataFrame到同一个Excel文件
with pd.ExcelWriter(r"D:\data\multi_sheet.xlsx") as writer:
df.to_excel(writer, sheet_name="Sheet1", index=False)
# 假设还有另一个 df2
df2.to_excel(writer, sheet_name="Sheet2", index=False)
7、数据操作

7.1、了解数据
- head():返回前n行(观察索引值),默认是5行
- tail():返回后n行(观察索引值),默认是5行
- info():查看数据表中所有列的数据类型。
- shape():以元组的形式返回行数、列数。注意shape方法获取行数和列数时不会把行索引和列索引计算在内。
- describe():获取所有数值类型字段的分布情况,即均值是多少、最值是多少、方差及分位数分别是多少。
7.2、DataFrame的列操作
7.2.1、新增列(或修改列)
1、基本语法
# 新增加一列。根据新数据添加,val是列值,index是行索引 df[cloumn_new] = pd.series([val1, val2, ..., val3], index=[index1, index2, ..., index3]) # 新增加一列。使用常数 df['cloumn_new’]=value df.cloumn_new=1 #注意不会报错!但并没有新增加一列 # 新增加一列。使用简单四则运算 df[cloumn_new] = df["cloumn1"] + df["cloumn2"] df['cloumn_new] = df[cloumn1'] * 100 df['cloumn_new] = df.cloumn1 * 100 # 新增加一列。使用内部函数计算 import math df['cloumn_new']=math.sqrt(value) df['cloumn_new']=math.sqrt(df.cloumn1) #报错:TypeError: cannot convert the series to <class 'float'> import numpy df['cloumn_new']=numpy.sqrt(df.cloumn1)
2、示例
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
df1["自然"] = pd.Series([99, 44, 55], index=[1, 3, 5])
df1["总分"] = df1["语文"] + df1["数学"] + df1["英语"] + df1["自然"]
7.2.2、删除列
1、基本语法
df.drop(
index=None, # 要删除的行索引,多个时用列表
columns=None, # 要删除的列索引,多个时用列表
inplace=Ture # 更改原数据,默认是False
)
# 直接删除原数据框相应的一列,建议尽量少用
del df["columns"]
del df.column # 不允许
# 删除并返回这一列(column)
df.pop(column)
2、示例
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 删除一行
df1.drop(index=2, inplace=True)
# 删除两列
df1.drop(columns=["姓名", "性别"], inplace=True)
# 删除一列
del df1["语文"]
# 不允许,报错AttributeError: 数学
del df1.数学
7.2.3、修改列值
1、整列统一修改
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
df1["语文"] = df1["语文"] + 100
2、只改满足条件的行的某列
- 见“条件筛选,筛选行”
7.2.4、获取列
1、基本语法
# 获取单列,结果为Series df.column df["column"] # 获取多列,结果为DataFream df[["column1", "column2", ..., "columnN"]]
2、示例
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
print(df1.姓名)
print(df1["姓名"])
print(df1[["姓名", "性别"]])
7.2.5、修改列名
1、基本语法
# 修改列名称,修改全部列名称(必须和源数据的列数一致)
df.columns = ["column1", "column2", ..., "columnN"]
# 修改列名称,修改指定列名称。该方法默认返回一个新对象
df.rename(
columns = {旧名称1:新名称1, 旧名称2:新名称2, ..., 旧名称N:新名称N},
inplace=True # 更改原数据,默认是False
)
2、示例
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
df1.columns = ["Name", "Sex", "Chinese", "Mathematics", "English"]
df1.rename(columns={"姓名": "Name", "英语": "English"}, inplace=True)
7.2.6、改变列顺序
1、按新的列顺序重新指定
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 手动调整顺序
df2 = df1[["姓名", "性别", "英语", "数学", "语文"]]
2、把某列移到最前面
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 手动调整顺序
cols = ["性别"] + [c for c in df1.columns if c != "性别"]
df2 = df1[cols]
7.2.7、条件筛选,筛选行
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 获取 "语文" > 60的行
print(df1[df1["语文"] > 60])
# 获取 "语文" > 60,且"数学" > 60的行
print(df1[(df1["语文"] > 60) & (df1["数学"] > 60)])
7.3、loc和iloc
- loc和iloc是pandas里最重要的两个索引方式,用来“按行+列”精确取数据、改数据。
- loc:按“标签”取/改(行索引名、列名)
- iloc:按“位置(下标)”取/改(第几行、第几列,从0开始)
- 索引方式不同:
- loc[行标签, 列标签]
- iloc[行位置, 列位置]
- 切片的左右端是否包含:
- loc包含右端的数据,即[]
- iloc不包含右端的数据,即[)
- 不要搞混标签和位置。假设行索引是 1, 2, 3(不是 0,1,2):
- df.loc[1],行标签为 1 的那一行
- df.iloc[1],“第二行”
7.3.1、loc按“标签”
1、获取行,按行标签(index)取
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl", index_col="姓名")
# 获取单行,取行标签为 "张三" 的那一行(Series)
print(df1.loc["张三"])
# 取多行(DataFrame)
print(df1.loc[["张三", "李四"]])
# 按标签切片,注意:**包含右端点** "李四"
print(df1.loc["张三": "李四"])
2、获取列:按列名取
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl", index_col="姓名")
# 获取单列,"语文"列(Series)
print(df1.loc[:, "语文"])
# 获取多列(DataFrame)
print(df1.loc[:, ["语文", "英语"]])
# 按标签切片
print(df1.loc[:, "语文":"英语"])
3、获取单元格:行列一起用
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl", index_col="姓名")
# 获取单值。获取"张三"的"数学"成绩
print(df1.loc["张三", "数学"])
# 获取连续范围的值。行:"张三": "李四", 列:"数学":"英语"
print(df1.loc["张三": "李四", "数学":"英语"])
4、条件筛选,筛选行
- 模式:df.loc[行条件, 列选择]
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl", index_col="姓名")
# 获取"语文" > 60 的行
df1.loc[df1["语文"] > 60, ["语文", "数学", "英语"]]
# 条件修改:"语文" > 60 的行,"英语" 加 100
df1.loc[df1["语文"] > 60, "英语"] = df1.loc[df1["语文"] > 60, "英语"] + 100
7.3.2、iloc按“位置”(整数下标)
1、获取行,按行位置取
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl", index_col="姓名")
# 获取单行,取行位置为 0 的那一行,即第一行(Series)
print(df1.iloc[0])
# 取多行(DataFrame)
print(df1.iloc[[0, 2]])
# 按标签切片,注意:**不包含右端点**
print(df1.iloc[0:2])
2、获取列:按列位置取
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl", index_col="姓名")
# 获取单列,"语文"列(Series)
print(df1.iloc[:, 0])
# 获取多列(DataFrame)
print(df1.iloc[:, [0, 3]])
# 按标签切片
print(df1.iloc[:, 1:3])
3、获取单元格:行列一起用
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl", index_col="姓名")
# 获取单值。第 2 行第 2 列的值
print(df1.iloc[1, 1])
# 获取连续范围的值。前3行前3列
print(df1.iloc[0: 3, 0:3])
4、条件筛选,筛选行(通常先用条件筛行,再 iloc 选列)
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl", index_col="姓名")
# 先按条件筛行,之后取第 1 到第 2 列
print(df1[df1["语文"] >= 60].iloc[:, 0:2])
7.4、操作单元格
1、获取、修改单元格
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 获取单元格
df1.姓名[1]
df1["姓名"][1]
df1.loc[1,"姓名"]
df1.iloc[1,0]
# 修改单元格(推荐使用loc、iloc)
df1.loc[1,"姓名"] = "倩倩"
# 条件筛选,修改指定列的值
df1["性别"][df1["性别"].isin(["男"])] = "man"
df1.性别[df1.性别.isin(["男"])] = "man"
df1.语文[df1.语文 == 88] = 188
df1[df1.语文 == 99].语文 = 199 # 注意,没修改,也没有报错
2、replace():替换匹配到的值
- 见“replace():替换匹配到的值”
8、索引
8.1、设置索引
1、基本语法
#指定某一列作为索引
df.set_index(
keys, #被指定为索引的列名,复合索引用list
drop=True, #建立索引后,删除该列
append=False, #不在原索引基础上添加索引,默认是直接替换原索引
inplace=False, #不修改原数据
erify_integrity=False #
)
#重置索引(重置索引为 0,1,2,...)
df.reset_index(
drop=False,
inplace=False
)
2、示例1
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 单索引
df1.set_index(keys='姓名', inplace=True, drop=False)
# 复合索引
df1.set_index(keys=['姓名', "性别"], inplace=True, drop=False)
3、示例2
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
df1.set_index(keys='姓名', inplace=True)
# 将索引还原列
# df1.reset_index(inplace=True)
# 删除索引
df1.reset_index(inplace=True, drop=True)
8.2、自定义索引
1、创建 DataFrame 时指定索引
# 创建数据时,创建索引
df = pd.DataFrame({'var1': 1.0,
'var2': [1, 2, 3, 4],
'var3': ['test', 'python', 'test', 'hello'],
'var4': 'cons'},
index=[1, 2, 3, 4])
2、后期直接赋值修改索引
import pandas as pd
df = pd.DataFrame({'var1': 1.0,
'var2': [1, 2, 3, 4],
'var3': ['test', 'python', 'test', 'hello'],
'var4': 'cons'},
index=[1, 2, 3, 4])
# 后期直接赋值修改索引
df.index = ["stu1", "stu2", "stu3", "stu4"]
8.3、引用和修改索引
- 注意:索引仍然是有存储格式的,注意区分数值型和字符型的引用方式
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl", index_col="姓名")
# 引用索引
df1.index
# 修改单索引名
df1.index.name = "name"
# 修改复核索引名
# df1.index.names = ['name', 'sex']
# 修改索引值
df1.index = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
8.4、更新索引
- reindex可以使用数据框中不存在的数值建立索引,并据此扩充新索引值对应的索引行/列,同时进行缺失值填充操作。
1、基本语法
df.reindex(
labels #类数组结构的数值,将按此数值重建索引,非必需
copy=True #建立新对象而不是直接更改原df/series缺失数据的处理方式
method #针对已经排序过的索引l,确定数据单元格无数据时的填充方法,非必需
pad/ffill #用前面的有效数值填充
backfill/bfill #用后面的有效数值填充
nearest #使用最接近的数值进行填充
fill_value=np.NaN #将缺失值用什么数值替代
limit=None #向前/向后填充时的最大步长
)
2、示例
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 索引存在,直接获取所在的行。索引不存在的,使用NaN填充
print(df1.reindex([1, 2, 3, 9, 10]))
# 缺值处理,使用前一个值填充
print(df1.reindex([1, 2, 3, 9, 10], method='ffill'))
# 缺值处理,使用指定值
print(df1.reindex([1, 2, 3, 9, 10], fill_value=5))
9、Pandas数据排序
- Pandas 里“排序”主要有两类:
- 按 值排序:sort_values()(最常用,按某一列或多列排序)
- 按 索引排序:sort_index()(按行索引或列索引的顺序)
1、基本语法
#按 值 排序
df.sort_values(
by, #单列排序或者多列排序(列表)
ascending=True, #升序排序(默认)。False降序排序
inplace=False, #不修改原数据
na_position="last" #缺失值的排列顺序,first/last
)
#按 索引 排序
df.sort_index(
level=None, #指定用于排序的级别顺序号/名称(多重索引时)
ascending=True, #升序排序。False降序排序
inplace=False, #不修改原数据
na_position="last" #缺失值的排列顺序,first/last
)
2、按值排序
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
#单字段排序
df2 = df1.sort_values(by='语文',ascending=False)
#多字段排序
df3 = df1.sort_values(by=['语文','数学'],ascending=[False,True])
3、按索引排序
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl", index_col=[0,1])
#单字段排序
df2 = df1.sort_index(level='姓名',ascending=False)
#多字段排序
df3 = df1.sort_index(level=['姓名','性别'],ascending=[False,True])
10、常用函数
10.1、isin():判断是否属于某个集合
- isin() 用来做“是否属于某个集合”的判断,非常适合用来按列表批量过滤行或列。
- 对 Series:判断每个元素是否在给定列表中,返回布尔 Series
- 对 DataFrame:对每个单元格判断,返回布尔 DataFrame
- isin() 右侧的“集合”可以是:
- list或元组:[1, 2, 3]
- set:{1, 2, 3}(大集合用 set 会更快)
- Series或Index:df["col"].isin(other_series)
- isin() 与 == 、in 的区别
- x in [1,2,3] 是对“单个值”判断
- df["col"] == 1 是对整列判断是否等于一个值
- df["col"].isin([1,2,3]) 是对整列判断是否在一组值中(更通用)
1、在Series上用isin(最常用场景)
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 返回布尔 Series
mask = df1["姓名"].isin(["张三", "李四", "王二"])
>>>print(mask)
0 True
1 False
2 False
3 True
4 True
5 False
6 False
7 False
8 False
Name: 姓名, dtype: bool
>>>print(df1[mask])
姓名 性别 语文 数学 英语
0 张三 男 88 11 99
3 李四 男 44 66 66
4 王二 男 55 33 99
2、在DataFrame上用isin
- 对整张表调用df.isin(values)会对每个单元格判断是否在values里,返回同样形状的布尔表。
- 一般不直接拿这个结果筛行,而是配合其它操作(比如统计、替换等)。
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
bool_df = df1.isin(["张三", 88])
>>>print(bool_df)
姓名 性别 语文 数学 英语
0 True False True False False
1 False False False False False
2 False False False False False
3 False False False False False
4 False False False False False
5 False False False False False
6 False False False False False
7 False False True False False
8 False False False True False
3、条件筛选,筛选行
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 用 isin 做“白名单过滤”
valid_ids = ["张三", "李四", "王二"]
df_valid = df1[df1["姓名"].isin(valid_ids)]
>>>print(df_valid)
姓名 性别 语文 数学 英语
0 张三 男 88 11 99
3 李四 男 44 66 66
4 王二 男 55 33 99
# 用 isin 做“黑名单过滤”(排除某些值)(~ 是取反)
valid_ids = ["张三", "李四", "王二"]
df_valid = df1[~df1["姓名"].isin(valid_ids)]
>>>print(df_valid)
姓名 性别 语文 数学 英语
1 小倩 女 77 55 33
2 小红 女 99 99 55
5 麻子 男 66 33 44
6 小翠 女 77 11 33
7 赵一 男 88 22 22
8 钱二 男 77 88 33
# 多个条件组合
df_filtered = df1[df1["性别"].isin(["男"]) & (df1["语文"] >= 60)]
>>>print(df_filtered)
姓名 性别 语文 数学 英语
0 张三 男 88 11 99
5 麻子 男 66 33 44
7 赵一 男 88 22 22
8 钱二 男 77 88 33
4、在多列上用 isin
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
cols = ["语文", "数学", "英语"]
values = [88, 99]
# 返回["语文", "数学", "英语"]三列中包含[88, 99]任意一个值的行
mask = df1[cols].isin(values).any(axis=1)
df_selected = df1[mask]
print(df_selected)
>>>
姓名 性别 语文 数学 英语
0 张三 男 88 11 99
2 小红 女 99 99 55
4 王二 男 55 33 99
7 赵一 男 88 22 22
8 钱二 男 77 88 33
cols = ["语文", "数学", "英语"]
values = [88, 99, 11]
# 返回["语文", "数学", "英语"]三列中包含[88, 99, 11]所有值的行
mask = df1[cols].isin(values).all(axis=1)
df_selected = df1[mask]
print(df_selected)
>>>
姓名 性别 语文 数学 英语
0 张三 男 88 11 99
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
mask = df1.isin({'语文': [88, 99], '性别': ['女']}).any(axis=1)
df_selected = df1[mask]
print(df_selected)
>>>
姓名 性别 语文 数学 英语
0 张三 男 88 11 99
1 小倩 女 77 55 33
2 小红 女 99 99 55
6 小翠 女 77 11 33
7 赵一 男 88 22 22
10.2、query():简化条件表达式
- query() 是 DataFrame 用来按“字符串表达式”筛选行的函数,相当于把之前用布尔条件写的过滤,写成一条更简洁的“类 SQL 语句”。
- 写法:df.query("条件表达式")
- 表达式里直接用“列名”当变量(比 df[df['col'] > 10] 更简洁)
- 支持的逻辑运算符:
- >、<、>=、<=、==、!=
- and、or 、not
- in、not in
- query 对列名有要求,特殊列名要用反引号包起来
1、单条件
# 普通写法
df1[df1["语文"] > 80]
# query写法
df1.query("语文 > 80")
2、多条件
# 普通写法
df1[(df1["语文"] > 60) & (df1["数学"] >= 60)]
# query写法
df1.query("语文 > 60 and 数学 > 60")
3、字符串/类别条件
(1)字符串等于某个值
- 注意:字符串常量要用引号包起来,可以用单引号 ' 或双引号 "。
df1.query("姓名 == '钱二'")
(2)多个取值之一(类似 isin)
#等价于df1[df1["姓名"].isin(["张三", "李四"])]
df1.query("姓名 in ['张三', '李四']")
4、query中使用变量(本地Python变量)
- 变量要用@引用
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
score = 60
df1.query("语文 > @score and 数学 > @score")
10.3、apply():调用func
- DataFrame.apply()
- 对DataFrame的每一列(axis=0,默认)或每一行(axis=1)调用func。
- func接收Series(raw=False时)或ndarray(raw=True时),返回标量/Series/list等。
- Series.apply()
- 对Series中每个元素或对整个Series(若func接收Series)进行操作(通常是按元素)。
#对DataFrame的每一列(axis=0,默认)或每一行(axis=1)调用func
df.apply(
func,
axis=0 #针对每列进行计算。1是针对每行进行计算
)
#对Series的每个值调用func
df['cloumn'].apply(
func,
convertDType
)
1、Series,对每个值使用内部函数
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
import numpy
#对语文列的每个值开平方
df1['cloumn_new']=df1['语文'].apply(numpy.sqrt)
2、Series,对每个值使用自定义函数
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
def fun(col):
col = col - 10
return col
#对语文列的每个值减10
df1['cloumn_new']=df1['语文'].apply(fun)
3、DataFrame,对每行、每列使用内部函数
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
df2 = df1[["语文", "数学", "英语"]]
# 每列求和
df2.apply(sum, axis=0)
# 每行求和
df2.apply(sum, axis=1)
4、DataFrame,对每行、每列使用自定义函数
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
df2 = df1[["语文", "数学", "英语"]]
def fun(arg):
print(arg)
# 打印每行,返回Series
df2.apply(fun, axis=0)
# 打印每行,返回Series
df2.apply(fun, axis=1)
10.4、assign():返回新的DataFrame
- signature: DataFrame.assign(**kwargs)
- 概述
- 功能:返回一个新的DataFrame,通过kwargs中指定的“表达式”新增或替换列(不在原地修改)。
- kwargs的值可以是标量、Series/ndarray/Index(会按照索引对齐或广播),也可以是可调用对象(callable),callable会以整个DataFrame作为参数被调用并应返回一个可赋给列的对象(Series/array/scalar)。
- 主要特性与规则
- 不会原地修改:assign返回的是新的DataFrame,原DataFrame保持不变(除非你把返回值赋回原变量)。
- 可链式调用友好:因为返回DataFrame,适合在方法链中使用(method chaining)。
- 可用可调用(callable)作为列值:callable会接收当前的DataFrame。使用callable(常见写法:lambda df: ...)。
- kwargs必须是合法的Python标识符(即作为关键字名),如果列名不是合法标识符,可用dict + **的方式传入。
- 如果传入Series,会根据索引对齐;传入标量则广播到所有行;传入长度不一致的可迭代对象会抛错。
- 多个kwargs按从左到右顺序求值,后面的可调用可以引用前面已创建的列。
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 新增简单列(标量/表达式)。总分是语文、数学、英语的和,cloumn_new1列的值都是常数5
df2 = df1.assign(总分=df1['语文'] + df1['数学'] + df1['英语'],cloumn_new1=5)
# 链式调用。总分是语文、数学、英语的和,然后将总分大于180的加10作为cloumn_new1
df3 = df1.assign(总分=lambda x: x.语文 + x.数学 + x.英语).query('总分 > 180').assign(cloumn_new1=lambda x: x.总分 + 10)
# 可用可调用作为列值。callable 接收整个 DataFrame(这里是 x),返回可赋给列的结果
df4 = df1.assign(语文=lambda x: x['语文'] + 100)
# 使用 Series 并按索引对齐
s = pd.Series([100, 200, 300], index=[0,1,2])
df5 = df1.assign(cloumn_new1=s)
# 多列且 callable 可引用前面创建的列(从左到右求值)
df6 = df1.assign(sum=lambda x: x.语文 + x.数学 + x.英语, double_sum=lambda x: x['sum'] * 2)
10.5、insert():插入新列,修改原DataFrame
- 特性
- 就地修改 DataFrame(inplace):会在原 DataFrame 上插入列并返回 None(不像 assign 返回新表)。
- 插入位置受 loc 控制(这是 insert 最大的优点:可以控制列的顺序)。
- 默认不允许重复列名,避免意外覆盖或混淆。
- Series 会按 index 对齐(不是简单位置对齐),这点与 df['col'] = series 相同。
- 在大表上虽然是“就地”API,但内部可能触发内存重分配或拷贝(取决于 pandas 实现),所以仍需关注性能与内存。
df.insert(
loc #整数,插入列的位置索引(0 表示最左侧,len(df.columns) 表示最右侧之后)。必须在 [0, n_columns] 范围内,否则会抛 IndexError。
column #要插入的列名(可以是任何可哈希对象,如字符串、元组,支持 MultiIndex 列名)。
value #要插入的值,可以是标量(会广播)、列表/ndarray、Series 或可被转换为列的对象。
#如果是 Series,会按索引对齐并填入 NaN(若索引不完全匹配)。
#如果是可迭代且长度与行数不匹配,会抛 ValueError。
allow_duplicates #默认 False。若为 False 且 column 名已存在,会抛 ValueError;若设为 True,则允许插入同名列(产生重复列名)。
)
示例:
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 在最前面增加一列,并用行索引加1000作为其值
df1.insert(0, "学号", df1.index + 1000)
# 在最后面增加一列,并用常数10作为其值
df1.insert(len(df1.columns), "附加分", 10)
10.6、replace():替换匹配到的值
- 用于把 DataFrame 或 Series 中匹配的值替换为其他值,功能比简单的赋值/map 更强,支持标量、列表、字典、正则表达式、按列映射等多种用法。
def replace(
to_replace=None,
value=None,
inplace: bool = False,
limit=None,
regex: bool = False,
method: str = "pad",
)
- 参数说明
- to_replace:要替换的值,可以是标量(如 0、'a')、list/tuple(如 [1,2])、dict(详见下)、正则表达式(当 regex=True 时)等。
- value:替换后的值(当 to_replace 是单个值或 list 时使用)。如果 to_replace 是 dict,则通常忽略 value(在 dict 中指定每个替换对)。
- inplace:是否就地修改(True)或返回新对象(False,默认)。
- limit:每个列/行允许的最大替换次数(按 API 语义是每列/每匹配项的上限)。
- regex:布尔或 dict。True 表示把字符串当正则表达式匹配;也可以对不同列使用不同的 regex(传 dict)。
- method:在某些 pandas 版本中,支持用前值/后值填充(如 'pad'/'ffill' 或 'bfill'),用法有限且版本差异存在。
示例:
import pandas as pd
import numpy as np
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
df1["自然"] = pd.Series(["1,001", "1,003", "1,005", "1,007"], index=[1, 3, 5, 7])
# 替换全表。把所有88替为188
df2 = df1.replace(88, 188)
# 替换全表。把 NaN 变为 0(注意:常用df.fillna(0))
df2 = df1.replace({np.nan: 0})
# 替换全表。把88或99都替成0
df2 = df1.replace([88,99], 0)
# 替换全表。把88、99分别替成188、199
df2 = df1.replace([88,99], [188,199])
# 替换全表。把88、99分别替成188、199
df2 = df1.replace({88:188, 99:199})
# 替换指定列(常用)。语文列把 88→188, 66→166;数学列把11→111)
df2 = df1.replace({'语文': {88: 188, 66: 166}, '数学': {11: 111}})
# 替换全表。使用正则,将逗号去掉
df2 = df1.replace(r"[\,]", "", regex=True)
# 替换指定列(修改原表)。使用正则,将逗号去掉
#df1["自然"].replace(r"[\,]", "", regex=True, inplace=True)
# 替换全表。使用 regex(例如把只含空白或 'n/a' 的标为 NaN)
df.replace({r'^\s*':np.nan, r'(?i)n/?a':np.nan}, regex=True)
11、分组
11.1、分组基本使用
- 基本概念
- 分割(split): 根据一个或多个键把数据分组。
- 应用(apply): 对每个分组执行聚合、转换或自定义操作。
- 合并(combine): 把每个分组的结果合并成最终的 Series/DataFrame。
- groupby 返回的是一个 GroupBy 对象(惰性计算),真正计算发生在调用 agg/transform/apply/filter/first/last 等方法时。
- 常见构造方式
- df.groupby('key'),单列分组
- df.groupby(['k1', 'k2']),多列分组
- df.groupby(df['date'].dt.month),用表达式或 Series 分组
- df.groupby(pd.Grouper(key='date', freq='M')),时间频率分组(按月)
- df.groupby(level=0),对 MultiIndex 的某一层分组
- df.groupby(['k1'], as_index=False),group keys 保持为列(默认 as_index=True)
1、基本语法
df.groupby(
by: MultiIndex | Any | None = ..., #用于分组的列名/函数
axis=0, #0(按行分组)或 1(按列分组,较少用)。
level: Any | None = ..., #用于 MultiIndex 指定层次。
as_index: Literal[True] = True, #True(默认)把分组键作为结果索引;False 则把分组键保留为列。
sort: bool = ..., #是否对组键排序(默认 True),若 False 则保留出现顺序(更快)。
group_keys: bool = ..., #在 apply 时是否把分组键加到结果索引/结果中(默认 True)。
observed: bool | Any = ..., #对分类变量分组时是否只考虑出现过的分类(默认为 False,True 可提高性能)。
dropna: bool = ...
) -> DataFrameGroupBy[tuple, Literal[True]]
2、示例
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 按单列分组
dfg = df1.groupby("性别")
# 按多列分组
#dfg = df1.groupby(['性别','语文'])
# 查看dfg里面的数据
print(dfg.groups)
# 查看具体描述(count、mean、min等)
print(dfg.describe())
# 查看分组数量
print(dfg.ngroups)
# 只适用单列分组
print(dfg.get_group('女').mean())
11.2、分组聚合
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 根据性别进行分组
dfg = df1.groupby('性别')
# (基本聚合)对表格进行聚合。获取每个分组的每列的和
df2 = dfg.agg(sum)
# (多函数聚合)对表格进行聚合。获取每个分组的,语文列的和、数学列的平均值、英语列的最大值
df3 = dfg.agg({'语文':'sum', '数学':'mean', '英语': 'max'})
# 对某列进行聚合。获取每个分组的,语文列的最大值
df4 = dfg["语文"].agg(max)
# 对某列进行聚合。获取每个分组的,语文、数学列的最大值和最小值
df5 = dfg["语文", "数学"].agg([max, min])
# 可以自定义函数
- 常用方法
- agg/aggregate:聚合(可接受函数名、函数列表、字典或命名聚合)。返回每组的标量或多列统计。
- transform:对每组返回与输入同长度的结果(常用于按组计算并广播回行级别,如归一化)。
- apply:把整个分组(DataFrame/Series)传入函数,自由度高,可返回任意形状,但常慢且要注意索引合并问题。
- filter:按组条件保留/丢弃整组(函数接收分组 DataFrame,返回 True/False)。
- get_group(name):返回指定组的 DataFrame。
- groups:字典,组键→行索引列表。
- size()/count():size 返回每组行数(计空值);count 忽略 NA。
- nth(n)/head(n)/tail(n):组内取第 n 条或前/后 n 条记录。
- ngroup():把组编号化(0..n-1)。
- cumcount():组内累积计数(常用于选 top-n)。
- rolling/expanding on groupby:groupby(...).rolling(...).mean() 等(注意索引需先 sort)。
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 根据性别进行分组
dfg = df1.groupby('性别')
# 命名聚合(pandas 0.25+ 推荐):
df2 = dfg.agg(total_val=('语文','sum'), avg_v2=('数学','mean'))
# transform 示例(组内标准化并返回与原表同形状)。语文列减其平均值,并赋值给语文_new列
df1['语文_new'] = dfg['语文'].transform(lambda x: (x - x.mean()))
# filter(只保留样本数 >= 3 的组)。返回组长度大于等于4
dfg3 = dfg.filter(lambda x: len(x) >= 4)
# apply 自定义(返回 DataFrame)。 nlargest用来快速取“值最大的前 n 个”。获取每组语文列最大的行
def top_row(g):
return g.nlargest(1, '语文')
dfg4=dfg.apply(top_row)
#获取每组 top n(更快的做法):
#idx = dfg['语文'].idxmax()
#df1.loc[idx]
#组内排名/编号:
df1['rank_in_group'] = dfg['语文'].rank(ascending=False)
df1['cumcount'] = dfg.cumcount()
12、数据合并
12.1、垂直合并
- 作用:
- DataFrame.append 用来把另一个 DataFrame、Series、字典或可迭代的这些对象“追加”到当前 DataFrame 的末尾,返回一个新的 DataFrame(不就地修改)。
- Series.append 则用于合并两个 Series,返回新的 Series。
- 重点:append 在 pandas 1.4 开始被弃用,并在后续版本移除。推荐使用 pd.concat 或直接赋值的方式替代。
- 注意:
- 返回新对象:append 不会就地修改原 DataFrame,你需要把结果赋回: df = df.append(new_row, ignore_index=True)
- 列对齐:当被追加对象的列与 df 不一致时,结果取并集,缺失处填 NaN。
- Series 追加:如果把 Series append 到 DataFrame(作为一行),Series 的索引会被当作列名进行对齐。
- dtype 变化:追加可能导致列 dtype 变化(例如把数值列与字符串合并会变为 object)。
- NA/缺失:如果索引不对齐会产生 NaN。
- 性能低:append 在循环中多次调用会导致 O(n^2) 的拷贝,效率很差。
df.append(
other #可以是 DataFrame、Series、字典或这些的列表/可迭代。
ignore_index=False #True 则重新索引(0..n-1);False 则保留原索引(可能出现重复索引)。
verify_integrity=False #True 时如果结果索引有重复会抛错(代价更高)。
)
示例:
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
# 追加一行(dict)
df2 = df1.append({'姓名':'黄酒','性别':'男','语文':'100'},ignore_index=True)
# 追加一个DataFrame
df3 = df1.append(df2, ignore_index=True)
# 追加多个DataFrame
df4 = df1.append([df2,df3], ignore_index=True)
12.2、水平合并
- DataFrame.merge是用于按一个或多个键把两个 DataFrame 进行关系型连接(类似 SQL 的 JOIN)。
- 常见 join 类型:inner(交集)、left(左表全部)、right(右表全部)、outer(并集)、cross(笛卡尔积)。
merge(
right: DataFrame | Series[Any],
how: Any = "inner",
on: Any | None = ...,
left_on: Any | None = ...,
right_on: Any | None = ...,
left_index: bool = False,
right_index: bool = False,
sort: bool = False,
suffixes: Any = ...,
copy: bool = True,
indicator: bool | str = False,
validate: Any | None = None
) -> DataFrame
- 参数说明:
- left, right:左/右 DataFrame。
- how:'left'/'right'/'inner'/'outer'/'cross'(默认为 'inner')。
- on:在左右表中同名列作为连接键(若未指定且左右均有相同列,会默认使用这些列)。
- left_on / right_on:分别指定左右表用于连接的列名或序列(用于列名不同时或其中一方用索引)。
- left_index / right_index:若为 True,则使用对应表的索引(Index)作为连接键(可与 left_on/right_on 组合使用以形成多键)。
- suffixes:当左右表存在同名非键列时,用于区分列名的后缀,如 ('_l','_r')。
- indicator:若 True,会在结果中加入一列 _merge(或指定名字)标明行来自 left/right/both,便于调试。
- validate:可选用于校验连接键的唯一性关系,参数值:
- 'one_to_one' / '1:1'
- 'one_to_many' / '1:m'
- 'many_to_one' / 'm:1'
- 'many_to_many' / 'm:m'(默认不校验)若校验失败会抛出异常,方便捕获逻辑错误。
- sort:是否按连接键对结果排序(默认 False 更快)。
- copy:是否复制数据(通常为 True)。
示例:
import pandas as pd
df1 = pd.DataFrame({
"A":["A0","A1","A2","A3","A4"],
"B":["B0","B1","B2","B3","B4"],
"C":["C0","C1","C2","C3","C4"]
})
df2 = pd.DataFrame({
"A":["A0","A1","A2","A3","A5"],
"C":["C0","C1","C2","C3","C5"],
"D":["A0","A1","A2","A4","A5"]
})
# 水平合并,默认是how = 'inner',做交集
df3 = pd.merge(df1, df2)
# 水平合并,做交集,并指定使用相同的列进行连接
df4 = pd.merge(df1, df2, on="A")
# 水平合并,做并集,并指定使用不同的列进行连接
df5 = pd.merge(df1, df2, how='outer', left_on="A", right_on="D")
# 水平合并,做交集,并指定使用索引进行连接
df1.set_index(keys='A')
df2.set_index(keys='D')
df6 = pd.merge(df1, df2, left_index=True,right_index=True)
12.3、按指定的轴合并
- 沿指定轴把多个 pandas 对象(DataFrame、Series 或这些对象的列表/字典)合并起来,类似 SQL/Excel 的“合并/合并”但按轴对齐索引/列。
concat(
objs: Iterable[NDFrame | None] | Mapping[HashableT1@concat, NDFrame | None],
*,
axis: Any = 0,
join: Literal['inner', 'outer'] = "outer",
ignore_index: bool = False,
keys: Iterable[HashableT2@concat] | None = None,
levels: Sequence[list[HashableT3@concat] | tuple[HashableT3@concat, ...]] | None = None,
names: list[HashableT4@concat] | None = None,
verify_integrity: bool = False,
sort: bool = False,
copy: bool = True
) -> DataFrame: ...
- 常用参数:
- objs:要合并的可迭代对象(list/tuple/dict)。若传 dict,键可作为 keys 用于产生 MultiIndex。
- axis:0(按行合并/纵向,默认)或 1(按列合并/横向)。
- join:'outer'(并集,默认,缺失处用 NaN 填充)或 'inner'(交集,只保留共有的索引/列)。
- ignore_index:若 True,重新生成连续数值索引(0..N-1),常用于垂直合并后丢弃原索引。
- keys:为每个被合并对象生成最外层的 MultiIndex(常用于保留来源标识或分组合并)。
- levels/names:与 keys 一起控制生成的 MultiIndex 的层级与命名。
- verify_integrity:若 True,会检查结果索引是否有重复(如有则抛错)。
- sort:控制在合并时是否对非对齐的索引/列进行排序(默认为 False,更快)。在某些 pandas 版本中若合并非对齐列会有警告,建议显式指定 sort。
- copy:是否复制数据(默认 True,通常不用改)。
示例:
import pandas as pd
df1 = pd.DataFrame({
"A":["A0","A1","A2","A3","A4"],
"B":["B0","B1","B2","B3","B4"],
"C":["C0","C1","C2","C3","C4"]
})
df2 = pd.DataFrame({
"A":["A0","A1","A2","A3","A5"],
"C":["C0","C1","C2","C3","C5"],
"D":["A0","A1","A2","A4","A5"]
})
# 水平合并(按 index 对齐列)
df3 = pd.concat([df1,df2], axis=1, ignore_index=True)
# 垂直合并
df4 = pd.concat([df1,df2], axis=0, ignore_index=True)
print(df3)
# 垂直合并,只保留共有列/索引(交集)
df5 = pd.concat([df1,df2], axis=0, ignore_index=True, join='inner')
# 使用 keys 生成 MultiIndex(保留来源)
df6 = pd.concat([df1,df2], keys=['df1','df2'])
# dict 作为 objs(键变为 keys):
df7 = pd.concat({'A': df1, 'B': df2})
13、长、宽格式
- stack(): 把列(column-level)搬到行索引(index-level),结果通常是 Series(带 MultiIndex)。
- unstack(): 把索引的一层搬到列上,结果通常是 DataFrame(把 index-level 变为 columns-level)。
df.stack(
level: Any = ...,
dropna: bool = ...,
sort: bool = ...,
future_stack: Literal[False] = False
) -> (DataFrame | Series[Any])
df.unstack(
self,
level: IndexLabel = -1,
fill_value: int | _str | dict | None = None,
sort: _bool = True,
) -> DataFrame: ...
- 常用参数:
- level(int、str 或 tuple):指定要搬动的层级(索引或列的层号或层名)。支持单层或多层。
- dropna(仅 stack):默认 True,表示丢弃全为 NaN 的条目;设为 False 可保留含 NaN 的组合(pandas 版本差异中有变动)。
- fill_value(unstack 的部分 pandas 版本支持):在 reshape 时用指定值填充缺失(若支持请参考你当前 pandas 版本文档)
示例:
import pandas as pd
df1 = pd.read_excel("stu_data.xlsx", engine="openpyxl")
#转化成 Series
df2 = df1.stack()
#恢复原 df
df3 = df2.unstack()
#数据转置
df4 = df1.T
14、缺失值
1、认识缺失值
import pandas as pd import numpy as np # 系统默认的缺失值是 None 和 np.nan df1 = pd.DataFrame([[1,None,3],[4,5,np.nan],[7,8,9]]) # info()方法返回每一列的缺失情况 df1.info() #如果是缺失值则返回True,如果不是缺失值返回False df1.isna() df1.isnull() #如果是缺失值则返回False,如果不是缺失值返回True df1.notna() df1.notnull() # any()默认axis=0,检查列,有缺失值为真 df1.isna().any(axis=0) # all()默认axis=0,检查列,全部是缺失值为真 df1.isna().all(axis=0)
2、填充缺失值
- fillna 用于把缺失值(NaN/None/pd.NA)替换为指定的值或用某种方法填充,常用于缺失值处理(单列、整表或按组填充)。
- 默认不就地修改(inplace=False),会返回新对象;可用 inplace=True 就地修改(小心 chained assignment)。
df.fillna(
value: Any | NAType | dict | Series[Any] | DataFrame | None = ...,
*,
axis: Any | None = ...,
limit: int = ...,
inplace: Literal[False] = False
) -> DataFrame
- 常用参数:
- alue:标量 / dict / Series / DataFrame(按列/索引对齐)。当为 dict 时,key 对应列名(axis 默认或 axis=0);当为 Series 时按索引对齐(DataFrame.fillna(df.mean()) 是常见写法)。
- method:填充方法,'ffill'/'pad' (向前填充),'bfill'/'backfill' (向后填充)。与 value 互斥(两者不能同时使用)。
- axis:{0/'index', 1/'columns'},按行或按列
- limit:仅对 method 生效,表示连续 NaN 最多填充多少个(控制跨度)。
- inplace:是否原地修改(True 就地,返回 None)。
- downcast:尝试在填充后把数据类型向更小类型转换(通常不常用)。
import pandas as pd
import numpy as np
# 系统默认的缺失值是 None 和 np.nan
df1 = pd.DataFrame({"A":[None,2,3],"B":[4,np.nan,6],"C":[7,8,None]})
#用标量填充整列/整表
#df1["A"] = df1["A"].fillna(0)
df2 = df1.fillna(0)
#按列指定不同填充值(dict)
df3 = df1.fillna({'A': 0, 'B': 'unknown', 'C': df1['C'].mean()})
#使用前值、后值填充
df4 = df1.fillna(method="ffill").fillna(method="bfill")
3、删除缺失值
- dropna 用于删除含有缺失值(NaN / None / NaT / pd.NA 等)的行或列。
df.dropna(
*,
axis: Any = ...,
how: Any = ...,
thresh: int | None = ...,
subset: Any | None = ...,
inplace: Literal[False] = False,
ignore_index: bool = ...
) -> DataFrame: ...
- 常用参数:
- axis: 0 或 'index'(按行删除,默认);1 或 'columns'(按列删除)。
- how: 'any'(默认)表示只要有任一 NAN 就删除;'all' 表示仅当全部为 NAN 时才删除。
- thresh: 整数,保留那些至少有 thresh 个非 NAN 值的行/列(优先级高于 how)。
- 例如 thresh=2 意味着“至少有 2 个非空值才保留”。
- subset: 列表/索引标签,指定在判断是否删除时只考虑的那些标签。
- 当 axis=0(按行)时,subset 指列名(只看这些列是否为 NAN来决定是否删除行)。
- 当 axis=1 时,subset 指索引标签(只看这些索引位置是否为 NAN 来决定是否删除列)。
- inplace: 是否就地修改(True 返回 None,False 返回新对象,默认 False)。
示例:
import pandas as pd
import numpy as np
df1 = pd.DataFrame({"A":[None,2,3,None],"B":[4,np.nan,6,None],"C":[7,8,9,None]})
#删除含任一 NAN 的行(默认):
df2 = df1.dropna()
#删除所有值都为 NAN 的行:
df3 = df1.dropna(how='all')
#删除含任一 NAN 的列:
df4 = df1.dropna(axis=1)
#删除所有值都为 NAN 的行:
df5 = df1.dropna(axis=1,how='all')
#仅根据部分列判断删除(如只要 'A' 为 NAN 就删该行):
df6 = df1.dropna(subset=['A'])
#仅当 'A' 与 'B' 都为 NAN 时才删除行:
df7 = df1.dropna(subset=['A','B'], how='all')
#保留至少两个非 NAN 的行:
df8 = df1.dropna(thresh=2)
15、重复行
- 两个核心函数
- duplicated(): 返回布尔 Series,标记每一行是否为重复(相对于之前出现过的行)。
- drop_duplicates(): 删除重复行,返回去重后的 DataFrame(默认不就地)。
1、标识重复行
duplicated(
subset: Hashable | Sequence[Hashable] | None = None,
keep: Literal["first"] | Literal["last"] | Literal[False] = "first",
)
- 常用参数:
- subset:用于判重的列名列表或单列;默认为 None 表示使用所有列。
- keep:{'first', 'last', False}
- 'first'(默认):保留第一次出现,后续重复项标 True;
- 'last':保留最后一次出现,前面的重复项标 True;
- False:把组内所有重复项都标为 True(不会保留任何重复项)。
示例:
import pandas as pd
import numpy as np
df1 = pd.DataFrame({"A":[1,1,3,4,3,5],"B":[1,1,3,4,3,1],"C":[1,1,3,4,3,5],"D":[1,1,3,4,3,5]})
#标记重复行(除第一次外)
#df1['is_dup'] = df1.duplicated()
#标记重复行(除第一次外),按指定列判断重复
#df1['is_dup'] = df1.duplicated(["B","C"])
#取出重复行(含所有重复项):
df2 = df1[df1.duplicated()]
#去掉重复(保留第一次):
df3 = df1[~df1.duplicated()]
2、删除重复行
drop_duplicates(
subset: Hashable | Iterable[Hashable] | None = ...,
*,
keep: Any = ...,
inplace: Literal[False] = False,
ignore_index: bool = ...
) -> DataFrame
- 常用参数:
- subset:用于判重的列名列表或单列;默认 None 表示用所有列判断重复。
- keep:{'first', 'last', False}
- 'first'(默认):保留第一次出现,删除后续重复行;
- 'last':保留最后一次出现,删除前面的重复行;
- False:删除所有出现多次的行(即完全移除重复组中所有行,仅保留出现一次的那些)。
- inplace:是否原地修改 DataFrame(True 返回 None);推荐默认 False,然后显式赋值以避免链式赋值问题。
- ignore_index:若 True,返回结果会重建连续整数索引(0..n-1)。
import pandas as pd
import numpy as np
df1 = pd.DataFrame({"A":[1,1,3,4,3,5],"B":[1,1,3,4,3,1],"C":[1,1,3,4,3,5],"D":[1,1,3,4,3,5]})
# 按全部列去重(保留第一次)
df2 = df1.drop_duplicates()
# 按指定列去重(只看特定列)
df3 = df1.drop_duplicates(["B","C"])
# 删除所有出现多次的行,只保留完全唯一的行
df4 = df1.drop_duplicates(keep=False)
16、时间
16.1、Timestamp和Period
- Timestamp:表示“时间点”(一个精确的瞬时点)。pandas.Timestamp 扩展自 Python 的 datetime,支持纳秒精度、时区(tz)、时间算术(Timedelta)等。
- Period:表示“时间区间/周期”(一个有频率的时段),例如“2020-01”(表示 2020 年 1 月这一整个月)、“2020Q1”(第一季度)。Period 有一个频率属性 freq(如 'D','M','Q','A' 等)。
示例:
import pandas as pd
from datetime import datetime
#直接创建
time1 = pd.Timestamp('2025-01-01')
time2 = pd.Timestamp('2025-01-01 1:2:3')
time3 = pd.Timestamp (2025,1,1,1,2,3)
#使用datetime
time4 = pd.Timestamp(datetime(2025,1,1))
time5 = pd.Timestamp(datetime(2025,1,1,1,2,3))
#从字符串/数组(更常用
time6 = pd.to_datetime('2025-01-01')
time7 = pd.to_datetime(['2025-01-01','2025-02-01'])
#常用属性:.year, .month, .day, .hour, .minute, .second, .microsecond, .nanosecond
time1.year
#常用属性:.weekday(), .dayofweek, .dayofyear, .is_month_end, .is_month_start 等
time1.weekday()
#从 Unix 时间/纳秒数:
# 以秒为单位
time8 = pd.Timestamp(1609459200, unit='s')
# 以纳秒整数
time9 = pd.to_datetime(1609459200000000000)
示例:
import pandas as pd
from datetime import datetime
#创建单个 Period:
time1 = pd.Period('2025-01', freq='M') # 2025 年 1 月(按月)
time2 = pd.Period('2025Q1', freq='Q') # 2025 第一季度
time3 = pd.Period('2025-01-15 1:2:3', freq='D') # 按日的周期(即那一天)
#从时间戳/字符串批量转 Period:
time4 = pd.to_datetime(['2025-01-03','2025-02-05']).to_period('M')
#生成 PeriodIndex(区间序列):
time5 = pd.period_range(start='2025-01', periods=6, freq='M')
#常用属性 / 方法(单个 Period)
time1.freq # 频率,如 'M'
time1.start_time # 返回该周期的起始 Timestamp(含时间)
time1.end_time # 返回该周期的结束 Timestamp
time1.asfreq(new_freq, how='start'/'end') # 改变频率并指定取哪端
time1.to_timestamp(how='start'/'end') # 转为 Timestamp(周期的起点或终点)
time1 + n / time1 - n # 按周期偏移(整数 n)
time1.ordinal # 内部序号(整数),可用于排序或比较
#把时间戳列转换为“所属月”再 groupby:
df1 = pd.DataFrame({"date":['2025-01-01 01:01:01', '2025-01-02 01:01:01', '2025-02-01 01:01:01', '2025-02-02 01:01:01'], 'A':[1,2,3,4]})
df1['month'] = pd.to_datetime(df1['date']).dt.to_period('M')
df1.groupby('month').groups
16.2、时间转换
import pandas as pd
from datetime import datetime
df1 = pd.DataFrame({"date":['2025-01-01 01:01:01', '2025-01-02 01:01:01', '2025-02-01 01:01:01', '2025-02-02 01:01:01']})
#使用pd.Timestamp()直接转换
#转换date列的第一个
time1 = pd.Timestamp(df1['date'][0])
#转换date列所有的
df_time2 = df1['date'].apply(pd.Timestamp)
#使用to_datetime转换
#转换date列所有
df_time3 = pd.to_datetime(df1['date'])
df2 = pd.DataFrame({'Year':[2025,2026], 'Month':[1,1], 'Day':[2,2], 'Hour':[3,3]})
df_time3 = pd.to_datetime(df2[['Year', 'Month', 'Day', 'Hour']])
16.3、时间索引
1、创建时间索引
import pandas as pd
from datetime import datetime
#创建DatetimeIndex对象
index1 = pd.DatetimeIndex(['2025-01-01 01:01:01', '2025-01-02 01:01:01', '2026-02-01 01:01:01', '2026-02-02 01:01:01'])
#创建DatetimeIndex对象,指定start、end
index2 = pd.date_range('2025-01-01', '2025-01-10')
#创建DatetimeIndex对象,指定个数,间隔是天
index3 = pd.date_range('2025-01-01', periods=10)
#创建DatetimeIndex对象,指定个数,并指定间隔是小时
index4 = pd.date_range('2025-01-01', periods=10, freq='H')
#创建DatetimeIndex对象,指定个数,并指定间隔是5小时
index5 = pd.date_range('2025-01-01', periods=10, freq='5H')
#创建DatetimeIndex对象,指定个数,间隔是天,并跳过休息日
index6 = pd.bdate_range('2025-01-01', periods=10)
2、使用时间索引
import pandas as pd
from datetime import datetime
df1 = pd.DataFrame({"date":['2025-01-01 01:01:01', '2025-01-02 01:01:01', '2026-02-01 01:01:01', '2027-02-02 01:01:01'], 'A':[1,2,3,4]})
#转化时间,并创建索引
df2 = df1.set_index(df1['date'].apply(pd.Timestamp))
#索引过滤
df2['2025']
df2['2025':'2026']
df2['2025-01']
df2['2025-01':'2026-02']
index对象
import pandas as pd # 创建index对象 ind = pd.Index([1, 2, 3, 4]) print(ind) # 获取元素, print(ind[0]) print(ind[-4]) print(ind[0:2]) print(ind[-4:-2]) print(ind[::2])
1
# #

浙公网安备 33010602011771号