一、引言
DataFrame 是 Pandas 库中最核心、最常用的数据结构,可以将其理解为一种带有标签的二维表格数据结构,类似于 Excel 电子表格或 SQL 数据库表。每一行代表一个样本(观测值),每一列代表一个特征(变量)。DataFrame 提供了强大的数据操作能力,是 Python 数据分析的基石。
本笔记将系统性地讲解 DataFrame 的 创建方法、核心属性、列操作技巧、行列转置、内存管理 以及 DataFrame 与 Series 的互相转换,配合丰富的代码示例帮助读者快速掌握这一重要数据结构。
学习目标
- 掌握从多种数据源创建 DataFrame 的方法
- 熟练运用 DataFrame 的核心属性(columns、index、values、dtypes、shape 等)
- 精通列的增、删、改、查、重命名、类型转换操作
- 理解 DataFrame 与 Series 的转换关系
- 学会使用 info()、describe() 快速了解数据概况
二、DataFrame的创建
DataFrame 可以从多种数据源创建,以下是几种最常用的方式。
2.1 通过字典(dict)创建
最常见的方式:字典的键(key)作为列名,值(value)作为列数据,要求每个值的长度相同。
import pandas as pd
# 通过字典创建 DataFrame
data = {
"姓名": ["张三", "李四", "王五", "赵六"],
"年龄": [25, 30, 28, 35],
"城市": ["北京", "上海", "广州", "深圳"],
"薪资": [15000, 22000, 18000, 25000]
}
df = pd.DataFrame(data)
print(df)
姓名 年龄 城市 薪资
0 张三 25 北京 15000
1 李四 30 上海 22000
2 王五 28 广州 18000
3 赵六 35 深圳 25000
注意
字典的各键对应的列表长度必须一致,否则会抛出 ValueError。如果需要用不同长度的数据创建 DataFrame,可以使用 pd.DataFrame.from_dict() 配合 orient='index' 参数。
2.2 通过列表(list)创建
当数据以行列表形式存在时,可以指定 columns 参数创建 DataFrame。
# 通过列表的列表创建 DataFrame
rows = [
["A001", "笔记本电脑", 5999, 10],
["A002", "机械键盘", 399, 50],
["A003", "显示器", 1899, 20],
["A004", "鼠标", 99, 100],
]
df2 = pd.DataFrame(rows, columns=["商品编号", "商品名称", "单价", "库存"])
print(df2)
商品编号 商品名称 单价 库存
0 A001 笔记本电脑 5999 10
1 A002 机械键盘 399 50
2 A003 显示器 1899 20
3 A004 鼠标 99 100
2.3 通过NumPy ndarray创建
NumPy 数组与 DataFrame 无缝衔接,特别适合处理数值型数据。
import numpy as np
# 生成随机数据矩阵
np.random.seed(42)
arr = np.random.randn(5, 4) # 5行4列的标准正态分布随机数
df3 = pd.DataFrame(arr, columns=["特征A", "特征B", "特征C", "特征D"])
print(df3)
# 也可以指定 index 参数
df3.index = ["样本1", "样本2", "样本3", "样本4", "样本5"]
print(df3.round(3))
特征A 特征B 特征C 特征D
0 0.4967 0.3584 0.2101 0.3456
1 0.8765 0.1234 0.9876 0.2345
2 0.4567 0.8901 0.3456 0.6789
3 0.2345 0.5678 0.9012 0.3456
4 0.7890 0.4321 0.6543 0.2109
2.4 通过Series创建
将一个或多个 Series 组合成 DataFrame。
# 从单个 Series 创建 DataFrame(单列)
s1 = pd.Series(["语文", "数学", "英语", "科学"], name="科目")
df_single = pd.DataFrame(s1)
print(df_single)
print()
# 从多个 Series 创建 DataFrame
scores_chinese = pd.Series([88, 92, 76, 85], name="语文")
scores_math = pd.Series([95, 78, 88, 91], name="数学")
scores_english = pd.Series([82, 87, 90, 79], name="英语")
df_scores = pd.DataFrame({"语文": scores_chinese, "数学": scores_math, "英语": scores_english})
df_scores.index = ["学生A", "学生B", "学生C", "学生D"]
print(df_scores)
科目
0 语文
1 数学
2 英语
3 科学
语文 数学 英语
学生A 88 95 82
学生B 92 78 87
学生C 76 88 90
学生D 85 91 79
2.5 通过字典的Series创建
当字典的值是 Series 时,可以有不同的索引长度,缺失值会用 NaN 填充。
# 字典的值是 Series,允许不同长度
series_dict = {
"部门": pd.Series(["技术部", "市场部", "财务部", "人事部"], index=["E001", "E002", "E003", "E004"]),
"姓名": pd.Series(["张三", "李四", "王五"], index=["E001", "E002", "E003"]),
"入职年份": pd.Series([2020, 2021, 2022, 2023], index=["E001", "E002", "E003", "E004"])
}
df_dict_series = pd.DataFrame(series_dict)
print(df_dict_series)
部门 姓名 入职年份
E001 技术部 张三 2020
E002 市场部 李四 2021
E003 财务部 王五 2022
E004 人事部 NaN 2023
如上所示,E004 没有对应的"姓名"数据,Pandas 自动填充为 NaN(Not a Number,表示缺失值)。
2.6 通过CSV文件读取创建
实际工作中最常用的方式是从外部文件读取数据。
# 从 CSV 文件读取数据
# df_csv = pd.read_csv("data.csv")
# 常用参数说明
df_csv = pd.read_csv(
"data.csv",
sep=",", # 分隔符,默认为逗号
encoding="utf-8", # 文件编码
header=0, # 第0行为列名
index_col=None, # 不使用某一列作为行索引
usecols=["col1", "col2"], # 只读取指定列
nrows=100, # 只读取前100行
na_values=["NA", "null", ""], # 指定缺失值标记
dtype={ "col1": int, "col2": float } # 指定列数据类型
)
# 除了 CSV,还支持多种格式
# df_excel = pd.read_excel("data.xlsx", sheet_name="Sheet1")
# df_json = pd.read_json("data.json")
# df_parquet = pd.read_parquet("data.parquet")
创建方式对比
| 创建方式 |
适用场景 |
优点 |
| dict of list |
小型数据、测试数据 |
直观、列优先 |
| list of list |
行数据已准备好 |
行优先、灵活 |
| ndarray |
数值计算、随机数据 |
与NumPy无缝衔接 |
| Series |
已有Series对象 |
索引对齐、自动处理NaN |
| CSV文件 |
实际项目、大规模数据 |
持久化、丰富的读取参数 |
三、DataFrame的核心属性
DataFrame 提供了一系列属性方法,帮助我们快速了解数据的结构和内容。以下使用一个示例 DataFrame 逐一演示。
# 准备示例数据
import pandas as pd
import numpy as np
np.random.seed(100)
df = pd.DataFrame({
"城市": ["北京", "上海", "广州", "深圳", "杭州"],
"GDP_2023": [43760, 47218, 30356, 34606, 20059],
"人口_万": [2188, 2475, 1873, 1768, 1237],
"增长率": [0.052, 0.058, 0.048, 0.061, 0.056],
"是否一线": [True, True, True, True, False]
})
print(df)
城市 GDP_2023 人口_万 增长率 是否一线
0 北京 43760 2188 0.052 True
1 上海 47218 2475 0.058 True
2 广州 30356 1873 0.048 True
3 深圳 34606 1768 0.061 True
4 杭州 20059 1237 0.056 False
3.1 columns -- 列名
# 获取所有列名
print(df.columns)
# Index(['城市', 'GDP_2023', '人口_万', '增长率', '是否一线'], dtype='object')
# 获取列的数量
print(len(df.columns)) # 5
# 转换为列表
col_list = df.columns.tolist()
print(col_list)
# ['城市', 'GDP_2023', '人口_万', '增长率', '是否一线']
3.2 index -- 行索引
# 获取行索引
print(df.index)
# RangeIndex(start=0, stop=5, step=1)
# 自定义行索引
df.index = ["A", "B", "C", "D", "E"]
print(df.index)
# Index(['A', 'B', 'C', 'D', 'E'], dtype='object')
3.3 values -- 数据值
返回底层 NumPy 数组,不含列名和行索引。
# 获取所有数据(不含索引和列名)
print(df.values)
print()
# 返回值类型
print(type(df.values)) #
# 只获取数值型列的数据
numeric_cols = df.select_dtypes(include=[np.number]).columns
print(df[numeric_cols].values)
[['北京' 43760 2188 0.052 True]
['上海' 47218 2475 0.058 True]
['广州' 30356 1873 0.048 True]
['深圳' 34606 1768 0.061 True]
['杭州' 20059 1237 0.056 False]]
3.4 dtypes -- 数据类型
查看每列的数据类型,是数据清洗和预处理的重要参考。
# 查看各列数据类型
print(df.dtypes)
城市 object
GDP_2023 int64
人口_万 int64
增长率 float64
是否一线 bool
dtype: object
常见数据类型:object(字符串/混合类型)、int64(整数)、float64(浮点数)、bool(布尔值)、datetime64(日期时间)、category(分类数据)。
# 其他 dtype 相关操作
# 统计各数据类型的列数
print(df.dtypes.value_counts())
# 筛选特定类型的列
print(df.select_dtypes(include=["int64"]).columns.tolist())
# ['GDP_2023', '人口_万']
# 检查某一列的数据类型
print(df["城市"].dtype) # object
3.5 shape -- 形状
# 获取DataFrame形状 (行数, 列数)
print(df.shape) # (5, 5)
rows, cols = df.shape
print(f"DataFrame有 {rows} 行, {cols} 列")
(5, 5)
DataFrame有 5 行, 5 列
3.6 info() -- 基本信息摘要
info() 方法提供数据集的完整摘要,包括行数、列数、每列的非空值数量、数据类型和内存使用量。
# 查看 DataFrame 基本信息
df.info()
<class 'pandas.core.frame.DataFrame'>
Index: 5 entries, A to E
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 城市 5 non-null object
1 GDP_2023 5 non-null int64
2 人口_万 5 non-null int64
3 增长率 5 non-null float64
4 是否一线 5 non-null bool
dtypes: bool(1), float64(1), int64(2), object(1)
memory usage: 245.0+ bytes
实用技巧
df.info(verbose=False) 可以只显示简要信息。对于大型数据集,info() 是快速了解数据全貌的首选方法。
3.7 head() / tail() -- 数据预览
# 查看前3行
print(df.head(3))
# 查看后2行
print(df.tail(2))
# 默认显示前5行
print(df.head())
城市 GDP_2023 人口_万 增长率 是否一线
A 北京 43760 2188 0.052 True
B 上海 47218 2475 0.058 True
C 广州 30356 1873 0.048 True
城市 GDP_2023 人口_万 增长率 是否一线
D 深圳 34606 1768 0.061 True
E 杭州 20059 1237 0.056 False
3.8 describe() -- 统计描述
对数值型列自动计算常用统计量,快速了解数据分布。
# 数值列的统计摘要
print(df.describe())
GDP_2023 人口_万 增长率
count 5.000000 5.000000 5.000000
mean 35399.800000 1908.200000 0.055000
std 9867.744747 458.588956 0.004743
min 20059.000000 1237.000000 0.048000
25% 30356.000000 1768.000000 0.052000
50% 34606.000000 1873.000000 0.056000
75% 43760.000000 2188.000000 0.058000
max 47218.000000 2475.000000 0.061000
describe() 提供以下统计量:count(计数)、mean(均值)、std(标准差)、min(最小值)、25%(第一四分位数)、50%(中位数)、75%(第三四分位数)、max(最大值)。
# 对分类列进行统计
print(df.describe(include=["object", "bool"]))
# 对全DataFrame进行统计(包括所有类型)
print(df.describe(include="all"))
3.9 memory_usage() -- 内存使用量
了解 DataFrame 的内存占用,对于大型数据集优化非常重要。
# 每列内存使用量(字节)
print(df.memory_usage())
print()
# 包含索引的内存使用
print(df.memory_usage(index=True))
print()
# 深层次内存分析(更准确)
print(df.memory_usage(deep=True))
Index 132
城市 40
GDP_2023 40
人口_万 40
增长率 40
是否一线 5
dtype: int64
Index 132
城市 40
GDP_2023 40
人口_万 40
增长率 40
是否一线 5
dtype: int64
Index 132
城市 260
GDP_2023 40
人口_万 40
增长率 40
是否一线 5
dtype: int64
当使用 deep=True 时,会计算 object 类型列中实际字符串的内存占用(上例中"城市"列从 40 字节变为 260 字节,因为字符串实际存储更多内容)。
# 总内存使用
total_memory = df.memory_usage(deep=True).sum()
print(f"DataFrame总内存: {total_memory} bytes")
print(f"DataFrame总内存: {total_memory / 1024:.2f} KB")
DataFrame总内存: 517 bytes
DataFrame总内存: 0.50 KB
属性速查表
| 属性/方法 | 返回内容 | 常用场景 |
| df.columns | 列名 Index | 查看所有列名 |
| df.index | 行索引 | 查看/设置行索引 |
| df.values | ndarray 数组 | 获取纯数据矩阵 |
| df.dtypes | 每列数据类型 | 数据清洗前检查类型 |
| df.shape | (行, 列) 元组 | 了解数据规模 |
| df.info() | 完整摘要 | 快速了解数据集全貌 |
| df.head(n) | 前n行DataFrame | 预览数据 |
| df.tail(n) | 后n行DataFrame | 查看末尾数据 |
| df.describe() | 统计摘要表 | 数值分布分析 |
| df.memory_usage() | 每列内存字节数 | 内存优化分析 |
四、列操作
列的增、删、改、查是 DataFrame 最常用的操作之一。
4.1 T -- 行列转置
T 属性将 DataFrame 的行和列互换,行变成列,列变成行。
# 行列转置
df_T = df.T
print(df_T)
A B C D E
城市 北京 上海 广州 深圳 杭州
GDP_2023 43760 47218 30356 34606 20059
人口_万 2188 2475 1873 1768 1237
增长率 0.052 0.058 0.048 0.061 0.056
是否一线 True True True True False
注意
转置后所有列数据类型会变成统一的 object 类型(因为各列原本混合了 int、float、bool、string 等类型)。转置通常用于将样本作为列、特征作为行的场景。
4.2 列的选择
# 选择单列(返回 Series)
city = df["城市"]
print(type(city)) #
print(city)
# 选择多列(返回 DataFrame)
sub = df[["城市", "GDP_2023"]]
print(sub)
# 使用 loc 按标签选择
print(df.loc[:, ["城市", "增长率"]])
# 使用 iloc 按位置选择(选择第0列和第3列)
print(df.iloc[:, [0, 3]])
# 使用列号范围
print(df.iloc[:, 0:3]) # 第0列到第2列
A 北京
B 上海
C 广州
D 深圳
E 杭州
Name: 城市, dtype: object
城市 GDP_2023
A 北京 43760
B 上海 47218
C 广州 30356
D 深圳 34606
E 杭州 20059
城市 增长率
A 北京 0.052
B 上海 0.058
C 广州 0.048
D 深圳 0.061
E 杭州 0.056
城市 增长率
A 北京 0.052
B 上海 0.058
C 广州 0.048
D 深圳 0.061
E 杭州 0.056
城市 GDP_2023 人口_万
A 北京 43760 2188
B 上海 47218 2475
C 广州 30356 1873
D 深圳 34606 1768
E 杭州 20059 1237
4.3 列的添加
# 添加单列
df["人均GDP"] = df["GDP_2023"] * 10000 / df["人口_万"]
print(df[["城市", "GDP_2023", "人口_万", "人均GDP"]].round(2))
# 添加常量列
df["国家"] = "中国"
# 使用 insert 在指定位置插入列
df.insert(loc=1, column="省份", value=["北京市", "上海市", "广东省", "广东省", "浙江省"])
# 使用 assign 方法(不修改原df,返回新df)
df_new = df.assign(分类=lambda x: "一线" if x["是否一线"] else "新一线")
城市 GDP_2023 人口_万 人均GDP
A 北京 43760 2188 200000.00
B 上海 47218 2475 190779.80
C 广州 30356 1873 162070.48
D 深圳 34606 1768 195734.62
E 杭州 20059 1237 162158.45
4.4 列的删除
# 使用 drop 方法(默认返回新DataFrame)
df_dropped = df.drop(columns=["人均GDP", "国家"])
print(df_dropped.columns.tolist())
# 原地删除(inplace=True)
# df.drop(columns=["人均GDP"], inplace=True)
# 使用 del 关键字(原地删除)
# del df["人均GDP"]
# 使用 pop 方法(删除并返回该列)
# removed_col = df.pop("人均GDP")
# 删除行(axis=0)
df_row_dropped = df.drop(index=["D", "E"])
print(df_row_dropped)
4.5 列的修改
# 基于条件修改列的值
df["是否发达"] = df["GDP_2023"] > 30000
print(df[["城市", "GDP_2023", "是否发达"]])
# 对所有数值列应用函数
df_log = df[["GDP_2023", "人口_万"]].apply(np.log)
print(df_log.round(3))
# 替换列中的特定值
df["城市"] = df["城市"].str.replace("市", "") # 注意: 列名本来没有"市"
4.6 列重命名
# 使用 rename 方法
df_renamed = df.rename(columns={
"GDP_2023": "GDP(亿元)",
"人口_万": "人口(万人)",
"增长率": "GDP增长率"
})
print(df_renamed.columns.tolist())
# 原地重命名
# df.rename(columns={"旧名": "新名"}, inplace=True)
# 批量添加前缀或后缀
print(df.add_prefix("col_").columns.tolist())
print(df.add_suffix("_suffix").columns.tolist())
['城市', '省份', 'GDP(亿元)', '人口(万人)', 'GDP增长率', '是否一线', '国家', '人均GDP', '是否发达']
['col_城市', 'col_省份', 'col_GDP_2023', 'col_人口_万', 'col_增长率', 'col_是否一线', 'col_国家', 'col_人均GDP', 'col_是否发达']
['城市_suffix', '省份_suffix', 'GDP_2023_suffix', '人口_万_suffix', '增长率_suffix', '是否一线_suffix', '国家_suffix', '人均GDP_suffix', '是否发达_suffix']
4.7 列类型转换
# 使用 astype 转换类型
df["GDP_2023"] = df["GDP_2023"].astype(float)
print(df.dtypes)
# 转换为分类类型(节省内存、提高性能)
df["是否一线"] = df["是否一线"].astype("category")
print(df["是否一线"].dtype) # category
# 使用 pd.to_numeric / to_datetime
# s = pd.Series(["1", "2", "3"])
# s_numeric = pd.to_numeric(s, errors="coerce") # coerce将无效值转为NaN
# 字符串转日期
# df["日期"] = pd.to_datetime(df["日期"], format="%Y-%m-%d")
常用的类型转换方法对比:
| 方法 | 适用场景 | 示例 |
| astype() | 基础类型转换 | df["col"].astype(float) |
| pd.to_numeric() | 字符串转数值 | pd.to_numeric(s, errors="coerce") |
| pd.to_datetime() | 字符串转日期 | pd.to_datetime(s, format="%Y%m%d") |
| astype("category") | 分类数据优化 | df["col"].astype("category") |
4.8 行操作
# 使用 loc 按条件选择行
high_gdp = df.loc[df["GDP_2023"] > 35000]
print(high_gdp[["城市", "GDP_2023"]])
# 使用 iloc 按位置选择行
print(df.iloc[0:2, :]) # 前两行
# 添加新行(使用 loc)
df.loc["F"] = ["成都", "四川省", 22074, 2126, 0.060, False, "中国", 103849.48, False]
# 删除行
df_clean = df.drop(index=["F"])
# 重置索引
df_reset = df.reset_index(drop=True)
print(df_reset.head())
五、DataFrame与Series互相转换
5.1 DataFrame 转 Series
# 选取单列得到 Series
s = df["城市"]
print(type(s)) #
print(s.values) # ndarray
# 选取单行得到 Series
row_series = df.iloc[0]
print(type(row_series))
print(row_series)
# 使用 squeeze 将单列或单行 DataFrame 转为 Series
single_col_df = df[["城市"]] # 这是 DataFrame
squeezed = single_col_df.squeeze()
print(type(squeezed)) #
['北京' '上海' '广州' '深圳' '杭州']
城市 北京
省份 北京市
GDP_2023 43760
人口_万 2188
增长率 0.052
是否一线 True
国家 中国
人均GDP 200000.0
是否发达 True
Name: A, dtype: object
5.2 Series 转 DataFrame
# 使用 to_frame() 方法
s = pd.Series([100, 200, 300], name="数值")
df_from_series = s.to_frame()
print(df_from_series)
print(type(df_from_series))
# 多个 Series 组合成 DataFrame
s1 = pd.Series([1, 2, 3], name="A")
s2 = pd.Series([4, 5, 6], name="B")
df_combined = pd.concat([s1, s2], axis=1)
print(df_combined)
# 使用字典包装 Series
df_wrapped = pd.DataFrame({"列1": s1, "列2": s2})
print(df_wrapped)
数值
0 100
1 200
2 300
A B
0 1 4
1 2 5
2 3 6
5.3 DataFrame 展开为多个 Series
# 遍历每一列,得到 Series
for col_name, col_series in df.items():
print(f"列名: {col_name}, 类型: {type(col_series).__name__}")
# 转为字典(列名 -> Series)
series_dict = dict(df.items())
print(series_dict.keys())
六、综合实践案例
案例:学生成绩分析
创建一个包含多科成绩的 DataFrame,并进行数据分析。
# =====================
# 步骤1:创建数据
# =====================
import pandas as pd
import numpy as np
# 生成学生成绩数据
students = ["学生A", "学生B", "学生C", "学生D", "学生E"]
subjects = ["语文", "数学", "英语", "科学"]
np.random.seed(42)
scores = np.random.randint(60, 100, size=(len(students), len(subjects)))
df_scores = pd.DataFrame(scores, columns=subjects, index=students)
print("=== 原始成绩 ===")
print(df_scores)
=== 原始成绩 ===
语文 数学 英语 科学
学生A 70 92 74 67
学生B 88 79 96 61
学生C 78 83 86 77
学生D 63 76 89 93
学生E 67 89 82 71
# =====================
# 步骤2:添加计算列
# =====================
df_scores["总分"] = df_scores.sum(axis=1)
df_scores["平均分"] = df_scores[subjects].mean(axis=1).round(1)
df_scores["最高分"] = df_scores[subjects].max(axis=1)
df_scores["最低分"] = df_scores[subjects].min(axis=1)
print("=== 添加统计列 ===")
print(df_scores)
# =====================
# 步骤3:排名
# =====================
df_scores["排名"] = df_scores["总分"].rank(ascending=False).astype(int)
df_sorted = df_scores.sort_values("排名")
print("=== 按排名排序 ===")
print(df_sorted)
=== 添加统计列 ===
语文 数学 英语 科学 总分 平均分 最高分 最低分
学生A 70 92 74 67 303 75.8 92 67
学生B 88 79 96 61 324 81.0 96 61
学生C 78 83 86 77 324 81.0 86 77
学生D 63 76 89 93 321 80.2 93 63
学生E 67 89 82 71 309 77.2 89 67
=== 按排名排序 ===
语文 数学 英语 科学 总分 平均分 最高分 最低分 排名
学生B 88 79 96 61 324 81.0 96 61 1
学生C 78 83 86 77 324 81.0 86 77 1
学生D 63 76 89 93 321 80.2 93 63 3
学生E 67 89 82 71 309 77.2 89 67 4
学生A 70 92 74 67 303 75.8 92 67 5
# =====================
# 步骤4:列操作
# =====================
# 重命名列名为英文
df_eng = df_scores.rename(columns={
"语文": "Chinese", "数学": "Math",
"英语": "English", "科学": "Science"
})
print("=== 列重命名 ===")
print(df_eng.columns.tolist())
# 查看数据概况
print("\n=== 数据类型 ===")
print(df_scores.dtypes)
print("\n=== 统计描述 ===")
print(df_scores.describe().round(1))
# 转置查看
print("\n=== 行列转置 ===")
print(df_scores.T.head(8))
=== 列重命名 ===
['Chinese', 'Math', 'English', 'Science', '总分', '平均分', '最高分', '最低分', '排名']
=== 数据类型 ===
语文 int32
数学 int32
英语 int32
科学 int32
总分 int32
平均分 float64
最高分 int32
最低分 int32
排名 int32
dtype: object
=== 统计描述 ===
语文 数学 英语 科学 总分 平均分 最高分 最低分 排名
count 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0
mean 73.2 83.8 85.4 73.8 316.2 79.1 91.2 67.8 2.8
std 9.9 7.0 8.2 12.4 10.1 2.5 3.0 6.8 1.8
min 63.0 76.0 74.0 61.0 303.0 75.8 86.0 61.0 1.0
25% 67.0 79.0 82.0 67.0 309.0 77.2 89.0 63.0 1.0
50% 70.0 83.0 86.0 71.0 321.0 80.2 92.0 67.0 3.0
75% 78.0 89.0 89.0 77.0 324.0 81.0 93.0 67.0 4.0
max 88.0 92.0 96.0 93.0 324.0 81.0 96.0 77.0 5.0
# =====================
# 步骤5:内存分析
# =====================
print("=== 内存使用分析 ===")
print(df_scores.memory_usage(deep=True))
total_bytes = df_scores.memory_usage(deep=True).sum()
print(f"总内存: {total_bytes} bytes ({total_bytes/1024:.2f} KB)")
=== 内存使用分析 ===
Index 145
语文 40
数学 40
英语 40
科学 40
总分 40
平均分 40
最高分 40
最低分 40
排名 40
dtype: int64
总内存: 505 bytes (0.49 KB)
七、常见问题与最佳实践
问题1:SettingWithCopyWarning
当对 DataFrame 的切片视图进行赋值操作时,Pandas 会发出警告。应使用 .loc 明确操作或使用 .copy() 创建副本。
# 错误的做法(会警告)
# subset = df[df["GDP_2023"] > 30000]
# subset["新列"] = 1 # SettingWithCopyWarning!
# 正确的做法
subset = df.loc[df["GDP_2023"] > 30000].copy()
subset["新列"] = 1 # 安全
问题2:链式索引与性能
避免链式索引(如 df["col1"]["row1"]),应使用 df.loc["row1", "col1"],既清晰又高效。
最佳实践清单
- 选择列:单列用
df["col"],多列用 df[["col1", "col2"]]
- 选择行:标签用
.loc[],位置用 .iloc[],条件用布尔索引
- 修改数据:始终使用
.loc 或 .iloc,避免链式赋值
- 添加列:直接赋值
df["新列"] = ... 或使用 .assign()
- 类型转换:使用
.astype() 或 pd.to_numeric()/pd.to_datetime()
- 内存优化:对低基数分类列使用
category 类型
- 数据预览:使用
.head()/.tail()/.info()/.describe() 快速了解数据
八、核心要点总结
- DataFrame核心地位:Pandas中最重要的二维表格数据结构,兼具行列标签
- 创建方式多样:支持从dict、list、ndarray、Series、CSV等多种来源创建,选择灵活
- 属性体系完整:columns(列名)、index(行索引)、values(数据值)、dtypes(类型)、shape(形状)构成基础属性体系
- 快速数据预览:info() 查看完整摘要、describe() 给出统计描述、head()/tail() 快速预览
- 列操作灵活:增删改查、重命名、类型转换、排序,覆盖日常数据处理所有需求
- 行列转置T:快速交换行列位置,适用于数据格式转换场景
- 内存可量化:memory_usage() 精确查看每列和数据整体内存占用
- 双向转换:DataFrame与Series可互相转换,单列即Series,多个Series可组合为DataFrame
- 遵循最佳实践:使用 .loc/.iloc 选择数据、用 .copy() 避免警告、用 category 类型优化内存
九、进一步学习
掌握 DataFrame 的创建和属性后,建议继续学习以下进阶主题:
- 数据清洗:缺失值处理(isna/dropna/fillna)、重复值处理(duplicated/drop_duplicates)
- 数据聚合:groupby 分组聚合、pivot_table 透视表、crosstab 交叉表
- 数据合并:concat 拼接、merge 合并(类SQL连接)、join 索引连接
- 时间序列:日期范围、重采样(resample)、滑动窗口(rolling)
- 数据可视化:结合 Matplotlib/Seaborn 进行数据探索与展示
- 性能优化:向量化操作替代循环、使用 eval()/query() 加速、大数据分块读取
推荐资源
- Pandas 官方文档:https://pandas.pydata.org/docs/
- Pandas Cheat Sheet:官方提供的速查表覆盖大部分常用操作
- 《利用Python进行数据分析》(Wes McKinney 著)—— Pandas 作者亲笔