当前位置:首页>python>Python 分析单细胞:pandas 数据框操作

Python 分析单细胞:pandas 数据框操作

  • 2026-10-11 05:50:18
Python 分析单细胞:pandas 数据框操作

前两篇我们分别学习了 Python 基础和 Python 进阶语法。这一篇专门讲 pandas 数据框 DataFrame 的操作。这篇只聚焦 pandas 本身,不展开 AnnData,也不系统讲 metadata 整理。因为后面介绍 AnnData、单样本和多样本数据处理时,adata.obs、adata.var、样本信息表和分组信息表,本质上都会大量用到 pandas DataFrame。


一、为什么单细胞分析要学 pandas?

在 Python 单细胞分析中,pandas 是非常重要的基础工具。

后面你会频繁看到:

adata.obsadata.var

它们看起来像普通表格,本质上就是 pandas DataFrame。

因此,在正式学习 AnnData 之前,先掌握 pandas 的常见操作会非常有帮助。

这一篇主要包括:

1. 创建 DataFrame2. 查看 DataFrame3. 读取 csv / tsv4. 行名和列名5. 提取行和列6. 条件筛选7. 增加、修改和删除8. 排序9. 分组统计10. 合并数据框

第一部分:创建 DataFrame

二、导入 pandas

使用 pandas 前,需要先导入:

import pandas as pd

通常约定把 pandas 简写成 pd。


三、用字典创建 DataFrame

先创建一个学生成绩表,方便理解数据框的基本操作。

import pandas as pddf = pd.DataFrame({ ”姓名”: [”李一”, ”燕三”, ”赵四”], ”语文”: [92, 82, 77], ”数学”: [98, 89, 92], ”英语”: [100, 92, 72]})df

结果:

姓名 语文 数学 英语0 李一 92 98 1001 燕三 82 89 922 赵四 77 92 72

这里可以理解为:

字典的 key 变成列名字典的 value 变成每一列的数据

四、把姓名作为行名

很多时候,我们希望姓名不是普通列,而是行名。

df = pd.DataFrame({ ”语文”: [92, 82, 77], ”数学”: [98, 89, 92], ”英语”: [100, 92, 72]}, index=[”李一”, ”燕三”, ”赵四”])df

结果:

语文 数学 英语李一 92 98 100燕三 82 89 92赵四 77 92 72

这里的 index 就是行名。

在单细胞分析里,barcode 通常也会作为行名。


第二部分:查看 DataFrame

五、查看前几行

df.head()

默认查看前 5 行。

如果想查看前 2 行:

df.head(2)

六、查看后几行

df.tail()

如果想查看后 2 行:

df.tail(2)

七、查看行列数

df.shape

输出类似:

(3, 3)

意思是:

3 行,3 列

八、查看列名和行名

查看列名:

df.columns

查看行名:

df.index

查看数据类型:

df.dtypes

第三部分:读取 csv 和 tsv 文件

九、读取 csv 文件

df = pd.read_csv(”data.csv”)

如果第一列是行名:

df = pd.read_csv(”data.csv”, index_col=0)

十、读取 tsv 文件

pandas 里面没有 pd.read_tsv()。

读取 tsv 要用:

df = pd.read_csv(”data.tsv”, sep=”\t”)

如果第一列是行名:

df = pd.read_csv(”data.tsv”, sep=”\t”, index_col=0)

十一、index_col=0 是什么意思?

index_col=0

意思是:

把第 0 列,也就是第一列,作为 DataFrame 的行名。

例如 tsv 文件长这样:

barcode in_tissue array_row array_colAAACAAGTATCTCCCA-1 1 50 102AAACAATCTACTAGCA-1 1 3 43

如果不加 index_col=0,barcode 会变成普通列。

如果加上:

df = pd.read_csv(”qc_metadata.tsv”, sep=”\t”, index_col=0)

那么 barcode 就会成为行名。


第四部分:提取列

十二、提取一列

df[”语文”]

结果是一个 Series:

李一 92燕三 82赵四 77Name: 语文, dtype: int64

十三、提取多列

df[[”语文”, ”数学”]]

结果仍然是 DataFrame:

语文 数学李一 92 98燕三 82 89赵四 77 92

注意:

df[”语文”]

是一列,返回 Series。

df[[”语文”]]

也是一列,但返回 DataFrame。


第五部分:提取行

十四、使用 loc 按行名提取

df.loc[”李一”]

提取李一这一行。

如果提取多行:

df.loc[[”李一”, ”赵四”]]

结果:

语文 数学 英语李一 92 98 100赵四 77 92 72

loc 是按名字提取。


十五、使用 iloc 按位置提取

df.iloc[0]

提取第 0 行,也就是第一行。

提取前两行:

df.iloc[0:2]

注意 Python 切片左闭右开:

0:2 取第 0 行和第 1 行,不取第 2 行

iloc 是按位置提取。


十六、loc 和 iloc 的区别

loc 按行名、列名提取iloc 按数字位置提取

例如:

df.loc[”李一”, ”语文”]

表示取李一的语文成绩。

df.iloc[0, 0]

表示取第 0 行、第 0 列的值。


第六部分:条件筛选

十七、筛选数学成绩大于 90 的学生

df2 = df[df[”数学”] > 90]df2

结果:

语文 数学 英语李一 92 98 100赵四 77 92 72

这里的逻辑是:

df[”数学”] > 90

先生成一组 True / False:

李一 True燕三 False赵四 TrueName: 数学, dtype: bool

然后用这组 True / False 筛选数据框。


十八、多条件筛选

例如筛选数学大于 90,并且英语大于 80 的学生:

df3 = df[ (df[”数学”] > 90) & (df[”英语”] > 80)]df3

在 pandas 里面:

and 要写成 &or 要写成 |not 要写成 ~

而且每个条件都要用小括号包起来。

错误写法:

df[(df[”数学”] > 90) and (df[”英语”] > 80)]

正确写法:

df[(df[”数学”] > 90) & (df[”英语”] > 80)]

十九、根据行名筛选

如果想提取王五和赵四:

df.loc[[”王五”, ”赵四”]]

如果想判断行名是否属于某几个值:

df[df.index.isin([”王五”, ”赵四”])]

区别是:

df.loc[[”王五”, ”赵四”]] 按指定顺序提取df[df.index.isin(...)] 按原数据框顺序筛选

第七部分:增加、修改和删除

二十、增加一列

df[”总分”] = df[”语文”] + df[”数学”] + df[”英语”]df

结果:

语文 数学 英语 总分李一 92 98 100 290燕三 82 89 92 263赵四 77 92 72 241

二十一、增加一行

最简单的方法是用 loc。

df.loc[”王五”] = [65, 66, 67, 198]df

如果当前数据框没有 总分 这一列,则写:

df.loc[”王五”] = [65, 66, 67]

二十二、用 concat 合并新增行

新版 pandas 中不推荐再使用 append(),更推荐 pd.concat()。

student_new = pd.DataFrame({ ”语文”: [65], ”数学”: [66], ”英语”: [67]}, index=[”王五”])df2 = pd.concat([df, student_new])df2

注意,新建 DataFrame 时,字典应该这样写:

pd.DataFrame({ ”语文”: [65], ”数学”: [66], ”英语”: [67]}, index=[”王五”])

不要写成多个字典:

pd.DataFrame({”语文”: ”65”}, {”数学”: ”66”}, {”英语”: ”67”}, index=[”王五”])

这种写法会报错。


二十三、修改某个值

例如修改王五的数学成绩:

df2.loc[”王五”, ”数学”] = 90df2

二十四、删除一列

删除 总分 这一列:

df2 = df2.drop(columns=[”总分”])

如果没有 总分 这一列,就不要执行这句。


二十五、删除一行

删除王五这一行:

df2 = df2.drop(index=[”王五”])

第八部分:排序

二十六、按数学成绩排序

升序:

df.sort_values(”数学”)

降序:

df.sort_values(”数学”, ascending=False)

二十七、按行名排序

df.sort_index()

第九部分:统计和分组

二十八、value_counts:统计每个值出现几次

例如统计每个语文成绩出现几次:

df[”语文”].value_counts()

如果想按分数排序:

df[”语文”].value_counts().sort_index()

二十九、groupby:分组统计

例如按语文成绩分组,统计每组人数:

df_yuwen = df.groupby(”语文”)df_yuwen.size()

结果类似:

语文65 177 182 192 2dtype: int64

这里左边的 65、77、82、92 是分组后的 index。右边的数字是每个分数出现的次数。

如果想变成普通数据框:

df_count = df.groupby(”语文”).size().reset_index(name=”人数”)df_count

结果:

语文 人数0 65 11 77 12 82 13 92 2

三十、按组计算平均值

例如按 cluster 计算平均 QC 指标:

qc_df.groupby(”clusters”)[[”n_genes_by_counts”, ”total_counts”]].mean()

虽然这里用了类似单细胞 QC 表的列名,但本质上仍然只是 pandas 的分组统计操作。


第十部分:合并数据框

三十一、concat:上下拼接

df_all = pd.concat([df1, df2])

适合把两个行结构相同的数据框上下合并。


三十二、concat:左右拼接

df_all = pd.concat([df1, df2], axis=1)

axis=1 表示按列拼接。


三十三、merge:按共同列合并

例如一个表是成绩,一个表是班级信息:

score_df = pd.DataFrame({ ”姓名”: [”李一”, ”燕三”, ”赵四”], ”语文”: [92, 82, 77]})class_df = pd.DataFrame({ ”姓名”: [”李一”, ”燕三”, ”赵四”], ”班级”: [”一班”, ”一班”, ”二班”]})

按姓名合并:

merged_df = pd.merge(score_df, class_df, on=”姓名”)merged_df

结果:

姓名 语文 班级0 李一 92 一班1 燕三 82 一班2 赵四 77 二班

第十一部分:常见错误

1. pandas 没有 read_tsv

错误:

df = pd.read_tsv(”data.tsv”)

正确:

df = pd.read_csv(”data.tsv”, sep=”\t”)

2. 筛选 df2 时不要用 df 的条件

错误:

df5 = df2[df[”数学”] > 90]

正确:

df5 = df2[df2[”数学”] > 90]

筛选哪个数据框,条件也尽量来自同一个数据框。


3. 多行行名筛选不能直接用 == 列表

错误:

df6 = df2[df2.index == [”王五”, ”赵四”]]

正确:

df6 = df2.loc[[”王五”, ”赵四”]]

或者:

df6 = df2[df2.index.isin([”王五”, ”赵四”])]

4. 增加行时 DataFrame 写法错误

错误:

student_new = pd.DataFrame({”语文”: ”65”}, {”数学”: ”66”}, {”英语”: ”67”}, index=[”王五”])

正确:

student_new = pd.DataFrame({ ”语文”: [65], ”数学”: [66], ”英语”: [67]}, index=[”王五”])

本篇小结

这一篇专门介绍了 pandas 数据框的基础操作:

1. 创建 DataFrame2. 查看 DataFrame3. 读取 csv / tsv 文件4. index_col=0 的含义5. 提取行和列6. loc / iloc7. 条件筛选8. 增加、修改和删除9. 排序10. value_counts 和 groupby11. concat 和 merge

这一篇先只讲 pandas 数据框本身,不展开 AnnData,也不讲复杂 metadata 整理。

下一篇可以正式进入:

AnnData 数据结构:认识 adata.X、adata.obs、adata.var、adata.uns、adata.obsm 和 adata.layers。

最新文章

随机文章