写在前面
踏入数据科学的世界,Pandas 无疑是 Python 生态中最闪耀的明星之一。它构建于 NumPy 之上,却带来了更强大、更灵活的数据处理能力,其核心数据结构 DataFrame 让表格数据的操作变得直观而高效。
本文将系统拆解 DataFrame 的各项关键操作,从基础的增删改查,到进阶的数据合并、分组与透视,一步步为您构建坚实的数据分析技能栈。
在上一篇 NumPy入门教程 的尾声,我们留下了三个小练习,帮助大家热热身。现在,让我们一起揭晓答案,巩固对 Pandas Series 和 DataFrame 基础的理解。
任务1:创建一个包含5个元素的Pandas Series,索引为字母a到e,值为1到5。
import pandas as pd
s = pd.Series([1, 2, 3, 4, 5], index=['a', 'b', 'c', 'd', 'e'])
print(s)
任务2:创建一个3行4列的DataFrame,列名为‘A’, ‘B’, ‘C’, ‘D’,数据自定。
data = {'A': [10, 20, 30],
'B': [1.1, 2.2, 3.3],
'C': ['X', 'Y', 'Z'],
'D': [True, False, True]}
df = pd.DataFrame(data)
print(df)
任务3:从上述DataFrame中选取‘B’列,并计算其平均值。
# 选取‘B’列
col_b = df['B']
# 计算该列的平均值
mean_b = col_b.mean()
print(f"B列的平均值为:{mean_b}")
DataFrame 是 Pandas 的灵魂,熟练掌握其基本操作是数据分析的第一步。
增:灵活添加新的数据维度。
# 添加一个新列‘E’
df['E'] = [100, 200, 300]
# 使用loc添加一行新数据
df.loc[3] = [40, 4.4, 'W', False, 400]
删:使用 drop() 方法精准移除行或列。默认生成新对象,设置 inplace=True 可直接修改原数据。
# 删除名为‘D’的列
df_dropped = df.drop(columns=['D'])
# 删除索引为3的行
df_dropped = df.drop(index=[3])
改:直接赋值,轻松更新数据。
# 修改单个单元格的值
df.loc[0, 'A'] = 99
# 将‘B’列的所有值翻倍
df['B'] = df['B'] * 2
查:通过多种方式定位所需数据(更详细的查询技巧见下文)。
删除列:除了 drop(),del 语句更为直接,但 drop() 功能更全面且可控。
del df['E'] # 从原DataFrame中直接删除列‘E’
去重:drop_duplicates() 是清理重复数据的利器。
# 基于所有列删除完全相同的行
df_unique = df.drop_duplicates()
# 仅针对‘A’和‘C’列进行去重
df_unique_subset = df.drop_duplicates(subset=['A', 'C'])
重命名列:让列名更清晰易懂。
df_renamed = df.rename(columns={'A': 'ID', 'B': 'Value'})
替换值:批量更新特定数据。
df_replaced = df.replace({'X': 'Alpha', 'Y': 'Beta'})
基于条件修改:实现智能化的数据更新。
# 将‘A’列大于25的行,其‘C’列的值标记为‘High’
df.loc[df['A'] > 25, 'C'] = 'High'
基于标签查询 (loc):使用行列的索引标签进行精确导航。
# 获取索引为0、列名为‘A’的单个值
value = df.loc[0, 'A']
# 选取多行多列
subset = df.loc[[0, 2], ['A', 'C']]
# 使用切片(注意:loc的切片包含结束位置)
slice_df = df.loc[0:2, 'A':'C']
基于位置查询 (iloc):使用整数位置进行快速定位。
# 获取第一行第一列的值
value = df.iloc[0, 0]
# 选取前两行、前三列(iloc切片不包含结束位置)
subset = df.iloc[0:2, 0:3]
布尔索引:通过逻辑条件筛选出目标数据,非常强大。
# 筛选出‘A’列大于20的所有行
filtered_df = df[df['A'] > 20]
# 组合多个条件进行复杂筛选
complex_filter = df[(df['A'] > 15) & (df['C'] == 'Y')]
按值排序:sort_values() 让数据井然有序。
# 按‘A’列升序排列
df_sorted = df.sort_values(by='A')
# 按‘A’列降序排列
df_sorted_desc = df.sort_values(by='A', ascending=False)
# 先按‘A’升序,再按‘B’降序排列
df_sorted_multi = df.sort_values(by=['A', 'B'], ascending=[True, False])
按索引排序:sort_index() 快速整理数据顺序。
df_sorted_index = df.sort_index(ascending=False) # 将索引按降序排列
现实数据常有不完美,缺失值(NaN)处理是数据清洗的关键环节。
检测缺失值:首先发现它们。
missing = df.isna() # 返回一个布尔矩阵,True代表缺失
missing_count = df.isna().sum() # 统计每列的缺失值数量
删除缺失值:dropna() 直接移除问题数据。
# 删除含有任何缺失值的行
df_no_na_rows = df.dropna()
# 删除整列都为缺失值的列
df_no_na_cols = df.dropna(axis=1, how='all')
# 仅删除在‘B’列上有缺失值的行
df_clean = df.dropna(subset=['B'])
填充缺失值:fillna() 用合理数值补全数据。
# 用0填充所有缺失值
df_filled = df.fillna(0)
# 使用前一个有效值向前填充
df_ffill = df.fillna(method='ffill')
# 用各列的平均值填充该列的缺失值
df_mean_fill = df.fillna(df.mean())
当数据分散在不同表格时,合并功能至关重要。
concat:主要用于简单堆叠,扩展数据维度。
df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})
# 纵向堆叠,增加行数
result_concat = pd.concat([df1, df2], ignore_index=True)
# 横向堆叠,增加列数
result_concat_col = pd.concat([df1, df2], axis=1)
merge:基于关键列进行连接,功能类似 SQL 的 JOIN。
left = pd.DataFrame({'key': ['K0', 'K1', 'K2'],
'A': ['A0', 'A1', 'A2']})
right = pd.DataFrame({'key': ['K0', 'K1', 'K3'],
'B': ['B0', 'B1', 'B3']})
# 内连接:只保留两个表都有的键
result_inner = pd.merge(left, right, on='key')
# 左连接:保留左表所有记录,右表匹配不上则为NaN
result_left = pd.merge(left, right, on='key', how='left')
# 外连接:保留所有记录,缺失部分用NaN填充
result_outer = pd.merge(left, right, on='key', how='outer')
groupby() 是洞察数据规律的显微镜,配合聚合函数,能快速生成统计摘要。
# 示例:不同部门的销售业绩
sales_data = pd.DataFrame({
'部门': ['销售部', '技术部', '销售部', '技术部', '销售部'],
'员工': ['张三', '李四', '王五', '赵六', '钱七'],
'销售额': [200, 150, 300, 180, 250]
})
# 按‘部门’分组,计算平均销售额和销售总额
grouped = sales_data.groupby('部门')['销售额'].agg(['mean', 'sum'])
print(grouped)
# 更灵活的分组聚合:对不同列应用不同函数
grouped_complex = sales_data.groupby('部门').agg({'销售额': 'sum', '员工': 'count'})
grouped_complex = grouped_complex.rename(columns={'员工': '人数'}) # 重命名结果列
print(grouped_complex)
pivot_table() 是进行多维数据汇总和交叉分析的瑞士军刀,一键生成复杂报表。
# 使用上面的销售数据
pivot = sales_data.pivot_table(
index='部门', # 行分组依据
values='销售额', # 需要汇总的数值列
aggfunc=['sum', 'mean', 'count'] # 应用的聚合函数
)
print(pivot)
# 进阶示例:假设数据包含‘年份’和‘产品’
# pivot_complex = df.pivot_table(index=['年份', '部门'], columns='产品', values='销售额', aggfunc='sum', fill_value=0)
光说不练假把式。现在,请运用本文所学的所有技能,完成下面的实战作业。它将带你体验一个完整的数据处理流程:从脏数据到清晰洞察。
作业数据集(请先运行以下代码创建DataFrame):
import pandas as pd
import numpy as np
data = {
'学生ID': ['S001', 'S002', 'S003', 'S004', 'S005', 'S002', 'S006'],
'姓名': ['张三', '李四', '王五', '赵六', '钱七', '李四', '孙八'],
'数学': [85, 90, 78, np.nan, 92, 90, 88],
'英语': [88, 92, 85, 70, np.nan, 92, 90],
'班级': ['A班', 'B班', 'A班', 'B班', 'A班', 'B班', 'A班']
}
df_students = pd.DataFrame(data)
print("原始数据:")
print(df_students)
你的任务清单:
数据清洗
数据查询与计算
数据排序
数据分组统计
(挑战题)数据合并
df_sports,包含 ‘学生ID’ 和 ‘体育’ 成绩(分数请自由设定)。how='left'),将 df_sports 合并到清洗后的 df_students 中。至此,我们已经系统遍历了 Pandas DataFrame 的核心操作版图。这条学习路径从最基础的增删改查出发,途经数据清洗的关卡(去重、处理缺失值),掌握了高效查询与排序的技巧,学会了如何合并多方数据,最终抵达了分组聚合与透视分析的高地。
掌握这些技能,意味着你已拥有独立处理和分析大部分结构化数据的工具箱。真正的掌握源于实践,请务必认真完成上面的作业,将知识转化为解决问题的能力。
| 基础操作 | df[‘col’] | ||
df[[‘col1’, ‘col2’]] | |||
df.loc[row, col] | df.loc[0, ‘A’]df.loc[:, ‘A’:‘C’] | ||
df.iloc[row_pos, col_pos] | df.iloc[0, 0]df.iloc[0:3, :] | ||
df.drop() | columns=[‘col’]index=[0], inplace=True | ||
df.rename() | columns={‘old’: ‘new’} | ||
| 数据清洗 | df.drop_duplicates() | subset=[‘col1’, ‘col2’] | |
df.isna()isnull() | |||
df.dropna() | axis=0/1how=‘any’/‘all’, subset=[‘col’] | ||
df.fillna() | value=0method=‘ffill’/‘bfill’ | ||
| 数据变形 | df.sort_values() | by=‘col’ascending=False | |
df.sort_index() | ascending=False | ||
pd.concat() | [df1, df2]axis=0/1, ignore_index=True | ||
pd.merge() | left, righton=‘key’, how=‘inner’/‘left’/‘outer’ | ||
| 分组聚合 | df.groupby() |
请在微信客户端打开