Pandas 数据分析 100 道基础练习题(附解析)

第1-20 题:数据创建、查看与基础操作

1. 导入 Pandas 和 NumPy 库,并打印它们的版本信息。

import pandas as pd
import numpy as np
print(f"Pandas version: {pd.__version__}")
print(f"NumPy version: {np.__version__}")

解析:这是使用 Pandas 和 NumPy 的第一步,通过 __version__ 属性可以确认库的版本,确保环境兼容性。

2. 从字典创建一个 DataFrame,字典内容为:{'A': [1, 2, 3], 'B': [4, 5, 6], 'C': [7, 8, 9]}

data = {'A': [1, 2, 3], 'B': [4, 5, 6], 'C': [7, 8, 9]}
df = pd.DataFrame(data)
print(df)

解析pd.DataFrame() 是创建 DataFrame 最常用的方法之一,可以直接将 Python 字典转换为表格结构,字典的键成为列名,值成为列数据。

3. 从 NumPy 数组创建一个 DataFrame,数组为 np.arange(12).reshape(3,4),列名为 ['W', 'X', 'Y', 'Z']

import numpy as np
arr = np.arange(12).reshape(3,4)
df = pd.DataFrame(arr, columns=['W', 'X', 'Y', 'Z'])
print(df)

解析pd.DataFrame() 也可以直接接收二维数组,并通过 columns 参数指定列名。np.arange(12).reshape(3,4) 生成一个 3行4列,从0到11的数组。

4. 读取名为 'data.csv' 的 CSV 文件到 DataFrame 中。

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

解析pd.read_csv() 是读取 CSV 文件的标准函数。默认第一行为列名。可以添加 encoding, sep 等参数处理不同格式的文件。

5. 查看上述 DataFrame 的前 3 行数据。

print(df.head(3))

解析df.head(n) 方法用于查看 DataFrame 的前 n 行,默认 n=5。这是数据探索的第一步,用于快速了解数据结构。

6. 查看上述 DataFrame 的后 5 行数据。

print(df.tail())

解析df.tail(n) 方法用于查看 DataFrame 的后 n 行,默认 n=5。常用于检查数据末尾的格式或内容。

7. 查看 DataFrame 的索引、列名、数据类型和非空值数量等摘要信息。

print(df.info())

解析df.info() 是数据预览的核心方法,能快速了解数据形状、每列数据类型及内存占用,是发现数据问题的第一步。

8. 查看 DataFrame 的维度(行数和列数)。

print(df.shape)

解析df.shape 返回一个元组 (行数, 列数),是获取数据规模最直接的方式。

9. 查看 DataFrame 的列名。

print(df.columns)

解析df.columns 返回一个 Index 对象,包含所有列名。了解列名是进行数据选择和操作的前提。

10. 查看 DataFrame 的索引。

print(df.index)

解析df.index 返回行索引信息。默认是 RangeIndex,也可以被设置为时间序列或其他类型。

11. 将 DataFrame 保存为名为 'output.xlsx' 的 Excel 文件。

df.to_excel('output.xlsx', index=False) # index=False 表示不保存行索引

解析df.to_excel() 用于将 DataFrame 写入 Excel 文件。index=False 是常用参数,避免将行索引作为额外一列写入。

12. 仅查看 DataFrame 中数值类型列(int, float)的统计摘要(如计数、均值、标准差、最小值、四分位数、最大值)。

print(df.describe())

解析df.describe() 默认只对数值列进行统计,生成计数、均值、标准差、最小值、25%/50%/75%分位数和最大值,是数据分布探索的关键工具。

13. 查看 DataFrame 中所有列(包括对象类型)的统计摘要。

print(df.describe(include='all'))

解析describe(include='all') 会对所有列进行统计。对于非数值列,它会显示唯一值数量、出现最频繁的值及其频次等。

14. 计算 DataFrame 中每一列的非空值数量。

print(df.count())

解析df.count() 返回每列非空(非NaN)值的数量,是检查数据完整性的基本方法。

15. 计算 DataFrame 中每一列的空值(NaN)数量。

print(df.isnull().sum())

解析df.isnull() 返回一个布尔型 DataFrame,指示每个元素是否为空。再使用 .sum() 对每列的 True 值(即空值)进行求和。

16. 删除 DataFrame 中任何包含空值的行。

df_cleaned = df.dropna()
print(df_cleaned.shape)

解析df.dropna() 默认删除任何包含至少一个空值的行。可通过 axis, how, thresh 等参数控制删除行为。

17. 删除 DataFrame 中 ‘col1’‘col2’ 这两列。

df_dropped = df.drop(['col1', 'col2'], axis=1)
print(df_dropped.columns)

解析df.drop() 用于删除行或列。指定列名列表和 axis=1(或 columns=['col1', 'col2'])表示删除列。axis=0 表示删除行。

18. 将 DataFrame 的索引重置为从 0 开始的连续整数,并将原来的索引作为新的一列 ‘old_index’

df_reset = df.reset_index(names='old_index')
print(df_reset.head())

解析df.reset_index() 将当前索引变为普通列,并新建一个默认的整数索引。names 参数可以为被重置的旧索引列命名。

19. 将 DataFrame 的 ‘date’ 列设置为索引。

df_indexed = df.set_index('date')
print(df_indexed.head())

解析df.set_index() 将指定列设置为新的行索引,常用于时间序列分析,便于基于时间的切片和重采样。

20. 创建一个 Series,数据为 [10, 20, 30, 40],索引为 [‘a’, ‘b’, ‘c’, ‘d’]

s = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])
print(s)

解析:Series 是带标签的一维数组。pd.Series(data, index) 是创建 Series 的基本方法,索引标签可用于数据选择。

第 21-40 题:数据选择与筛选

21. 使用 iloc 选择 DataFrame 的第 2 行(索引为 1)数据。

row_2 = df.iloc[1]
print(row_2)

解析df.iloc[] 基于整数位置进行选择。df.iloc[1] 选择第二行(从0开始计数),返回一个 Series。

22. 使用 loc 选择索引标签为 ‘row2’ 的行数据。

row_label = df.loc['row2']
print(row_label)

解析df.loc[] 基于索引标签进行选择。前提是索引包含标签 ‘row2’。如果索引是默认整数,则 df.loc[1]df.iloc[1] 效果相同。

23. 使用 iloc 选择 DataFrame 的第 1 到第 3 行(不包含第3行),以及第 0 和第 2 列。

subset = df.iloc[0:2, [0, 2]] # 行切片 0:2 表示 0,1;列列表 [0,2] 表示第1和第3列
print(subset)

解析iloc 支持行和列的切片与列表选择。切片 0:2 遵循“左闭右开”原则。列选择 [0, 2] 表示一个索引列表。

24. 使用 loc 选择索引标签从 ‘A’‘C’ 的行,以及列名为 [‘col1’, ‘col3’] 的列。

subset = df.loc['A':'C', ['col1', 'col3']] # 注意标签切片 'A':'C' 是闭区间
print(subset)

解析loc 的标签切片是闭区间,即包含起始和结束标签。这与 iloc 的整数切片不同。

25. 选择 DataFrame 中名为 ‘age’ 的单个列。

age_series = df['age'] # 或 df.age (不推荐,当列名与DataFrame方法冲突时会出错)
print(type(age_series)) # 输出:<class 'pandas.core.series.Series'>

解析:使用方括号 df[‘col_name’] 是选择单列的标准方式,返回一个 Series。点号语法 df.col_name 虽然方便,但不够健壮。

26. 选择 DataFrame 中名为 [‘name’, ‘score’] 的多列。

multi_cols = df[['name', 'score']]
print(type(multi_cols)) # 输出:<class 'pandas.core.frame.DataFrame'>

解析:在方括号内传入一个列名的列表,可以选择多列,返回一个新的 DataFrame。

27. 筛选出 ‘score’ 列大于 90 的所有行。

high_scores = df[df['score'] > 90]
print(high_scores)

解析df[‘score’] > 90 会生成一个布尔型 Series。将其放入 df[] 中,会返回所有对应位置为 True 的行。这是 Pandas 中最核心的布尔索引操作。

28. 筛选出 ‘department’ 列等于 ‘Sales’‘salary’ 大于 50000 的所有行。

filtered = df[(df['department'] == 'Sales') & (df['salary'] > 50000)]
print(filtered)

解析:多个条件组合时,每个条件必须用括号 () 括起来,并使用位运算符 & (与)、| (或)、~ (非) 连接,不能使用 and, or, not

29. 筛选出 ‘city’ 列在列表 [‘Beijing’, ‘Shanghai’, ‘Guangzhou’] 中的行。

cities = ['Beijing', 'Shanghai', 'Guangzhou']
in_cities = df[df['city'].isin(cities)]
print(in_cities)

解析Series.isin(list) 方法用于检查 Series 的每个元素是否存在于给定的列表中,返回布尔 Series,常用于多值筛选。

30. 筛选出 ‘email’ 列包含字符串 ‘@gmail.com’ 的所有行。

gmail_users = df[df['email'].str.contains('@gmail.com', na=False)]
print(gmail_users)

解析Series.str.contains(pattern) 用于字符串匹配。na=False 参数确保当遇到空值(NaN)时返回 False 而不是 NaN,避免筛选错误。

31. 使用 query 方法筛选出 age 大于 30 且 gender‘M’ 的行。

filtered_query = df.query('age > 30 and gender == "M"')
print(filtered_query)

解析df.query() 方法允许使用字符串表达式进行查询,语法更接近自然语言。注意字符串常量需要用双引号。

32. 随机从 DataFrame 中抽取 5 行数据(不放回)。

sampled = df.sample(n=5, random_state=42) # random_state 确保结果可复现
print(sampled)

解析df.sample() 用于随机抽样。n 指定抽样数量,random_state 设置随机种子以保证结果可重复。

33. 提取 DataFrame 中 ‘value’ 列最大的前 3 行。

top3 = df.nlargest(3, 'value')
print(top3)

解析df.nlargest(n, columns) 返回指定列值最大的前 n 行。对应的 df.nsmallest() 返回最小的前 n 行。比先排序再取头部更直观。

34. 选择 DataFrame 中所有数据类型为 ‘object’的列。

object_cols = df.select_dtypes(include=['object'])
print(object_cols.columns)

解析df.select_dtypes() 根据数据类型选择列。include 参数指定要包含的类型,exclude 指定要排除的类型。

35. 使用 at 方法快速获取索引为 5、列名为 ‘price’ 的单个值。

value = df.at[5, 'price']
print(value)

解析df.at[]df.iat[] 用于快速访问单个标量值,速度比 loc/iloc 更快。at 基于标签,iat 基于整数位置。

36. 使用 iat 方法快速获取第 0 行、第 2 列(从0计数)的单个值。

value = df.iat[0, 2]
print(value)

解析df.iat[0, 2] 等价于 df.iloc[0, 2],但 iat 是专门为访问单个标量优化的方法。

37. 筛选出 ‘col1’ 列的值不在另一个 Series s 中的行。

# 假设 s 是一个 Series
not_in_s = df[~df['col1'].isin(s)]
print(not_in_s)

解析~ 是位取反运算符。df[‘col1’].isin(s) 返回布尔 Series,~ 将其反转,从而选择不在 Series s 中的行。

38. 提取 ‘category’ 列中出现频率最高的值。

most_frequent = df['category'].mode()[0] # mode() 返回一个Series,可能有多值,取第一个
print(most_frequent)

解析Series.mode() 返回众数,即出现频率最高的值。由于可能存在多个众数,它返回一个 Series,通常取第一个元素 [0]

39. 提取 ‘id’ 列中能被 5 整除的所有值。

divisible_by_5 = df[df['id'] % 5 == 0]['id']
print(divisible_by_5)

解析:利用取模运算符 % 和布尔索引。df[‘id’] % 5 == 0 生成布尔掩码,筛选出行后再选择 ‘id’ 列。

40. 计算 ‘value’ 列中每个值与其前一行的差值(第一行差值为 NaN)。

df['value_diff'] = df['value'].diff()
print(df[['value', 'value_diff']].head())

解析Series.diff(periods=1) 计算当前元素与前一个元素的差值,是时间序列分析中计算增量的常用方法。periods 参数可调整间隔。

第 41-60 题:数据清洗与转换

41. 将 DataFrame 的列名 [‘A’, ‘B’, ‘C’] 改为 [‘X’, ‘Y’, ‘Z’]

df.rename(columns={'A': 'X', 'B': 'Y', 'C': 'Z'}, inplace=True)
print(df.columns)

解析df.rename(columns=dict) 用于重命名列。inplace=True 表示直接修改原 DataFrame,否则会返回一个新 DataFrame。

42. 将 DataFrame 的索引名改为 ‘ID’

df.index.name = 'ID'
print(df.index.name)

解析:DataFrame 的索引可以有一个名字,通过 df.index.name 属性直接设置或修改。

43. 将 DataFrame 中 ‘amount’ 列的数据类型从 ‘object’ 转换为 ‘float’

df['amount'] = df['amount'].astype(float)
print(df['amount'].dtype)

解析Series.astype(dtype) 是转换数据类型的主要方法。转换失败(如字符串包含非数字字符)会报错,需先处理。

44. 将 ‘date_string’ 列(格式如 ‘2023-01-15’)转换为 Pandas 的 datetime 类型。

df['date'] = pd.to_datetime(df['date_string'])
print(df['date'].dtype)

解析pd.to_datetime() 是解析日期时间字符串的强大函数,能自动识别多种格式。转换后便于进行时间序列操作。

45. 将 ‘price’ 列中所有大于 100 的值替换为字符串 ‘High’

df.loc[df['price'] > 100, 'price'] = 'High'
print(df['price'].unique())

解析:使用 df.loc[布尔条件, 列名] 定位到满足条件的特定单元格,然后进行赋值修改。

46. 使用 ‘Unknown’ 填充 DataFrame 中所有空值(NaN)。

df_filled = df.fillna('Unknown')
print(df_filled.isnull().sum())

解析df.fillna(value) 用指定值填充所有空值。也可以传入字典为不同列指定不同的填充值,如 df.fillna({‘col1’: 0, ‘col2’: ‘missing’})

47. 使用 ‘salary’ 列的平均值填充该列的空值。

mean_salary = df['salary'].mean()
df['salary'].fillna(mean_salary, inplace=True)

解析:这是处理数值列缺失值的常见策略。也可以使用中位数 .median() 或众数 .mode()[0] 进行填充。

48. 删除 DataFrame 中 ‘col1’ 列完全为空(全部为 NaN)的行。

df_dropped = df.dropna(subset=['col1'], how='all')

解析df.dropna(subset=[列列表]) 只检查指定列是否有空值。how=‘all’ 表示只有当指定列全部为空时才删除该行。

49. 删除 DataFrame 中重复的行(基于所有列判断)。

df_deduped = df.drop_duplicates()
print(f"原始行数: {len(df)}, 去重后行数: {len(df_deduped)}")

解析df.drop_duplicates() 默认基于所有列判断重复,保留第一次出现的行。可用 subset 参数指定依据列,keep 参数控制保留哪一行。

50. 删除 DataFrame 中在 [‘col1’, ‘col2’] 这两列上重复的行,只保留最后一次出现的行。

df_deduped_last = df.drop_duplicates(subset=['col1', 'col2'], keep='last')

解析subset 指定判断重复的列组合。keep=‘last’ 保留最后一次出现的行,keep=False 会删除所有重复行。

51. 将 DataFrame 中 ‘status’ 列的值进行映射:{1: ‘Active’, 0: ‘Inactive’}

mapping = {1: 'Active', 0: 'Inactive'}
df['status_label'] = df['status'].map(mapping)
print(df[['status', 'status_label']].head())

解析Series.map(dict_or_series) 是进行值映射的便捷方法。它根据映射关系将 Series 中的每个值替换为新值。

52. 将 DataFrame 中 ‘grade’ 列的值使用 apply 方法转换为大写。

df['grade_upper'] = df['grade'].apply(lambda x: x.upper() if isinstance(x, str) else x)
print(df[['grade', 'grade_upper']].head())

解析Series.apply(func) 将函数应用于 Series 的每个元素。这里使用 lambda 函数和条件判断,确保只对字符串类型应用 .upper()

53. 使用 cut 函数将 ‘age’ 列分为 3 个区间:(0, 18], (18, 60], (60, 100],并命名为 [‘Young’, ‘Adult’, ‘Senior’]

bins = [0, 18, 60, 100]
labels = ['Young', 'Adult', 'Senior']
df['age_group'] = pd.cut(df['age'], bins=bins, labels=labels, right=True)
print(df[['age', 'age_group']].head())

解析pd.cut() 用于将连续数值分箱(离散化)。bins 定义区间边界,labels 定义区间标签,right=True 表示区间右闭(如 (0,18])。

54. 使用 qcut 函数将 ‘income’ 列按分位数分为 4 组(四分位)。

df['income_quartile'] = pd.qcut(df['income'], q=4, labels=['Q1', 'Q2', 'Q3', 'Q4'])
print(df['income_quartile'].value_counts())

解析pd.qcut() 基于样本分位数进行分箱,确保每个分组有大致相同数量的数据点。q=4 表示分为4组(四分位)。

55. 对 DataFrame 按 ‘department’ 列进行分组,并计算每组 ‘salary’ 的平均值。

avg_salary_by_dept = df.groupby('department')['salary'].mean()
print(avg_salary_by_dept)

解析df.groupby(‘分组列’)[‘计算列’].聚合函数() 是分组聚合的标准模式。.mean() 是聚合函数之一。

56. 对 DataFrame 按 [‘year’, ‘month’] 进行分组,并计算每组中 ‘sales’ 的总和与 ‘profit’ 的平均值。

grouped = df.groupby(['year', 'month']).agg({'sales': 'sum', 'profit': 'mean'})
print(grouped.head())

解析df.groupby().agg(dict) 可以对不同的列应用不同的聚合函数。字典的键是列名,值可以是聚合函数字符串(如 ‘sum’)或函数对象。

57. 在分组后,重置索引,使分组键(‘year’, ‘month’)重新变为普通列。

grouped_reset = grouped.reset_index()
print(grouped_reset.head())

解析groupby 操作后,分组键默认成为结果的索引。reset_index() 将其还原为普通列,便于后续合并或分析。

58. 计算 ‘col1’ 列与 ‘col2’ 列之间的欧氏距离(假设每行是一个点)。

import numpy as np
df['euclidean_dist'] = np.sqrt((df['col1'] - df['col2']) ** 2)
print(df[['col1', 'col2', 'euclidean_dist']].head())

解析:欧氏距离公式为 sqrt((x1-x2)^2)。这里利用 Pandas Series 的向量化运算,直接对整个列进行计算,无需循环。

59. 将 DataFrame 的列顺序从 [‘A’, ‘B’, ‘C’, ‘D’] 改为 [‘D’, ‘A’, ‘C’, ‘B’]

df = df[['D', 'A', 'C', 'B']]
print(df.columns)

解析:通过使用包含新顺序列名的列表对 DataFrame 进行索引,可以重新排列列的顺序。

60. 交换 DataFrame 中 ‘col1’‘col2’ 两列的位置。

col_names = list(df.columns)
idx1, idx2 = col_names.index('col1'), col_names.index('col2')
col_names[idx1], col_names[idx2] = col_names[idx2], col_names[idx1]
df = df[col_names]
print(df.columns)

解析:通过获取列名列表,交换目标列名的索引位置,然后按新列表重新索引 DataFrame,实现列位置交换。

第 61-80 题:数据统计、排序与聚合

61. 按 ‘score’ 列对 DataFrame 进行降序排序。

df_sorted = df.sort_values(by='score', ascending=False)
print(df_sorted.head())

解析df.sort_values(by, ascending) 是主要的排序方法。by 指定排序列,ascending=False 表示降序。

62. 按 [‘dept’, ‘salary’] 进行排序,先按 ‘dept’ 升序,再按 ‘salary’ 降序。

df_sorted_multi = df.sort_values(by=['dept', 'salary'], ascending=[True, False])
print(df_sorted_multi.head())

解析by 参数可以接收列名列表,实现多列排序。ascending 参数也对应地接收一个布尔值列表,分别指定每列的排序方向。

63. 计算 ‘age’ 列的中位数。

median_age = df['age'].median()
print(f"年龄中位数: {median_age}")

解析Series.median() 计算中位数,对异常值不敏感,是描述数据集中趋势的稳健指标。

64. 计算 ‘salary’ 列的总和与平均值。

salary_sum = df['salary'].sum()
salary_mean = df['salary'].mean()
print(f"总和: {salary_sum}, 平均值: {salary_mean}")

解析sum()mean() 是基本的描述性统计方法。对于数值列,它们忽略 NaN 值。

65. 计算 ‘col1’ 列的标准差和方差。

std_dev = df['col1'].std()
variance = df['col1'].var()
print(f"标准差: {std_dev}, 方差: {variance}")

解析std() 计算样本标准差(默认分母为 n-1),var() 计算样本方差。它们是衡量数据离散程度的重要指标。

66. 计算 ‘value’ 列的偏度(Skewness)和峰度(Kurtosis)。

skewness = df['value'].skew()
kurtosis = df['value'].kurt()
print(f"偏度: {skewness:.2f}, 峰度: {kurtosis:.2f}")

解析:偏度衡量数据分布的不对称性(正偏表示右尾长)。峰度衡量分布形态的陡峭程度(与正态分布相比)。

67. 计算 ‘category’ 列中每个唯一值的出现次数。

value_counts = df['category'].value_counts()
print(value_counts)

解析Series.value_counts() 返回唯一值及其计数,默认按计数降序排列。是分类数据探索的必备工具。

68. 计算 ‘category’ 列中每个唯一值的出现频率(百分比)。

value_counts_pct = df['category'].value_counts(normalize=True) * 100
print(value_counts_pct)

解析value_counts(normalize=True) 返回的是比例(总和为1),乘以100即得到百分比。

69. 对 DataFrame 按 ‘group’ 列分组后,计算每组的大小(行数)。

group_sizes = df.groupby('group').size()
print(group_sizes)

解析groupby().size() 返回每个分组中的行数。与之类似的 groupby().count() 返回的是每列的非空值计数。

70. 计算 ‘sales’ 列的累计和。

df['cumulative_sales'] = df['sales'].cumsum()
print(df[['sales', 'cumulative_sales']].head())

解析Series.cumsum() 计算累计和。类似的还有 cumprod() (累计积)、cummax() (累计最大值)、cummin() (累计最小值)。

71. 计算 ‘price’ 列的 3 期简单移动平均(例如,当前行与前两行的平均值)。

df['price_ma_3'] = df['price'].rolling(window=3, min_periods=1).mean()
print(df[['price', 'price_ma_3']].head())

解析Series.rolling(window).mean() 计算滚动窗口平均值,常用于平滑时间序列数据。min_periods=1 表示即使窗口内数据不足也进行计算。

72. 找出 ‘value’ 列中的局部最大值(即比前一个和后一个值都大的点)。

# 方法:比较当前值是否大于前一个值和后一个值
local_max = df[(df['value'] > df['value'].shift(1)) & (df['value'] > df['value'].shift(-1))]
print(local_max[['value']])

解析:使用 shift(1) 获取前一行的值,shift(-1) 获取后一行的值。通过布尔索引找出同时大于两者的点。

73. 计算 DataFrame 中每列的平均值。

col_means = df.mean(numeric_only=True) # numeric_only=True 只计算数值列
print(col_means)

解析df.mean() 默认对每列进行计算,返回一个 Series。numeric_only=True 是 Pandas 2.0 后的推荐写法,避免对非数值列计算报错。

74. 计算 DataFrame 中每行的最大值。

row_max = df.max(axis=1, numeric_only=True)
print(row_max.head())

解析axis=1 表示按行进行计算。numeric_only=True 确保只考虑数值列。

75. 对 ‘data’ 列应用自定义函数:如果值大于100 则标记为 ‘High’,否则标记为 ‘Normal’

def classify_value(x):
    return 'High' if x > 100 else 'Normal'

df['data_class'] = df['data'].apply(classify_value)
print(df[['data', 'data_class']].head())

解析apply 可以应用自定义函数。这里定义了一个简单的分类函数,对 Series 的每个元素进行判断并返回标签。

76. 使用 pivot_table 创建数据透视表,以 ‘Year’ 为行,‘Product’ 为列,‘Sales’ 为值,聚合函数为求和。

pivot = pd.pivot_table(df, values='Sales', index='Year', columns='Product', aggfunc='sum', fill_value=0)
print(pivot)

解析pd.pivot_table() 是创建数据透视表的强大工具。values 指定要聚合的列,indexcolumns 指定行和列的分组键,aggfunc 指定聚合函数,fill_value 填充缺失值。

77. 使用 crosstab 计算 ‘Gender’‘Department’ 的交叉频数表。

cross_tab = pd.crosstab(df['Gender'], df['Department'])
print(cross_tab)

解析pd.crosstab() 专门用于计算两个或多个因子的简单交叉表(频数统计)。比 pivot_table 在计算频数时更简洁。

78. 计算 ‘col1’‘col2’ 两列之间的相关系数。

correlation = df['col1'].corr(df['col2'])
print(f"相关系数: {correlation:.2f}")

解析Series.corr(other_series) 计算皮尔逊相关系数,衡量两个变量间的线性相关程度(-1 到 1 之间)。

79. 计算整个 DataFrame 数值列之间的相关系数矩阵。

corr_matrix = df.corr(numeric_only=True)
print(corr_matrix)

解析df.corr() 计算 DataFrame 中所有数值列两两之间的相关系数,返回一个对称矩阵。常用于探索特征间的关系。

80. 对 ‘amount’ 列进行标准化(Z-score 标准化):(x - mean) / std。

df['amount_zscore'] = (df['amount'] - df['amount'].mean()) / df['amount'].std()
print(df[['amount', 'amount_zscore']].head())

解析:Z-score 标准化将数据转换为均值为0、标准差为 1 的分布。这是许多机器学习算法的常见预处理步骤。

第 81-100 题:高级操作与综合应用

81. 将两个 DataFrame df1df2 按行上下拼接(要求列相同)。

df_concat = pd.concat([df1, df2], ignore_index=True)
print(df_concat.shape)

解析pd.concat([df1, df2], axis=0) 是沿行方向(axis=0)拼接多个 DataFrame。ignore_index=True 会重置索引,生成新的连续整数索引。

82. 将两个 DataFrame df1df2 按列左右拼接(要求行索引相同)。

df_concat_col = pd.concat([df1, df2], axis=1)
print(df_concat_col.shape)

解析axis=1 表示沿列方向拼接。要求两个 DataFrame 的行索引对齐,否则会产生 NaN。

83. 基于 ‘key’ 列,使用 mergedf_leftdf_right 进行内连接(inner join)。

df_merged = pd.merge(df_left, df_right, on='key', how='inner')
print(df_merged.head())

解析pd.merge() 是类似 SQL JOIN 的合并操作。on 指定连接键,how=‘inner’ 表示内连接,只保留两个 DataFrame 中都有的键。

84. 基于 [‘key1’, ‘key2’] 两列,对 df_leftdf_right 进行左连接(left join)。

df_left_merged = pd.merge(df_left, df_right, on=['key1', 'key2'], how='left')
print(df_left_merged.head())

解析on 参数可以接收一个列名列表,实现多键连接。how=‘left’ 表示左连接,保留左表所有行,右表匹配不上的填充 NaN。

85. 使用 join 方法,基于索引将 df1df2 连接起来。

df_joined = df1.join(df2, how='inner')
print(df_joined.head())

解析df1.join(df2) 默认基于索引进行连接,是 merge 的一个便捷特例。how 参数同样控制连接类型。

86. 将 ‘date’ 列设置为索引后,提取 2023 年 1 月份的所有数据。

df_date_index = df.set_index('date')
jan_2023_data = df_date_index['2023-01']
print(jan_2023_data.head())

解析:当索引是 DatetimeIndex 时,可以使用部分字符串索引进行便捷的切片,如 ‘2023-01’ 选择整个一月份的数据。

87. 对以日期为索引的 DataFrame,按周(‘W’)重采样并计算每周的 ‘sales’ 总和。

weekly_sales = df.resample('W', on='date')['sales'].sum()
print(weekly_sales.head())

解析df.resample(freq) 是时间序列重采样的核心方法。‘W’ 表示按周(周日为每周最后一天)。on 参数指定日期时间列(如果该列不是索引)。

88. 将 ‘long_format_df’从长格式转换为宽格式,其中 ‘date’ 为索引,‘variable’ 列的值成为新列名,‘value’ 列的值成为单元格值。

df_wide = long_format_df.pivot(index='date', columns='variable', values='value')
print(df_wide.head())

解析df.pivot() 用于数据透视,将长格式数据转换为宽格式。它要求 (index, columns) 组合是唯一的,否则会报错(此时需用 pivot_table)。

89. 将宽格式的 df_wide 转换回长格式,新的列名为 [‘date’, ‘variable’, ‘value’]

df_long = df_wide.reset_index().melt(id_vars='date', var_name='variable', value_name='value')
print(df_long.head())

解析df.melt()pivot 的逆操作,将宽格式“融化”为长格式。id_vars 指定保持不变的列,var_namevalue_name 为新列命名。

90. 对 DataFrame 应用一个函数,计算每行的 ‘col1’‘col2’ 之和,结果存入新列 ‘sum_col’

df['sum_col'] = df.apply(lambda row: row['col1'] + row['col2'], axis=1)
print(df[['col1', 'col2', 'sum_col']].head())

解析df.apply(func, axis=1) 将函数应用于每一行。axis=1 是关键,表示按行操作。函数参数 row 是一个 Series,代表该行数据。

91. 使用 eval 方法高效计算新列 ‘result’,其值为 (colA * 2 + colB) / colC

df.eval('result = (colA * 2 + colB) / colC', inplace=True)
print(df[['colA', 'colB', 'colC', 'result']].head())

解析df.eval() 使用字符串表达式进行列间运算,通常比 apply 更快,因为它利用了 Pandas 的底层优化。

92. 找出 DataFrame 中 ‘col’ 列最大的前 5 个值的索引。

top5_idx = df['col'].nlargest(5).index
print(list(top5_idx))

解析Series.nlargest(5) 返回最大的 5 个值及其索引。.index 属性提取这些索引。

93. 将 DataFrame 中所有小于 0 的值替换为 0。

df_clipped = df.clip(lower=0)
print(df_clipped.head())

解析df.clip(lower, upper) 将小于 lower 的值替换为 lower,大于 upper 的值替换为 upper。这是数据裁剪的便捷方法。

94. 计算 ‘col’ 列的指数加权移动平均(EWMA),跨度(span)为 5。

df['col_ewma'] = df['col'].ewm(span=5, adjust=False).mean()
print(df[['col', 'col_ewma']].head())

解析Series.ewm() 计算指数加权移动平均,对近期数据赋予更高权重。span 参数与衰减因子相关,adjust=False 使用递推公式。

95. 将 DataFrame 按 ‘group’ 列分组,并对每个分组内的 ‘value’ 列进行标准化(组内Z-score)。

def zscore_within_group(x):
    return (x - x.mean()) / x.std()

df['value_group_z'] = df.groupby('group')['value'].transform(zscore_within_group)
print(df[['group', 'value', 'value_group_z']].head())

解析groupby()[‘col’].transform(func) 对每个分组应用函数,但返回与原始数据形状相同的结果,非常适合组内标准化这类操作。

96. 展开 ‘list_col’ 列(该列每个元素是一个列表),使列表中的每个元素成为独立的一行。

df_exploded = df.explode('list_col')
print(df_exploded.head())

解析df.explode(column) 将指定列中类似列表的每个元素展开为一行,并复制其他列的值。用于处理嵌套数据。

97. 计算 ‘col’ 列的百分位数:第 25%(Q1)、第 50%(中位数)、第 75%(Q3)。

q1 = df['col'].quantile(0.25)
median = df['col'].quantile(0.50)
q3 = df['col'].quantile(0.75)
print(f"Q1: {q1}, Median: {median}, Q3: {q3}")

解析Series.quantile(q) 计算分位数,q 介于 0和 1 之间。Q1、中位数、Q3 是描述数据分布和识别异常值的关键。

98. 基于 ‘col’ 列的值,使用 between 方法筛选出值在 10 到 20 之间(包含两端)的所有行。

filtered_between = df[df['col'].between(10, 20, inclusive='both')]
print(filtered_between.head())

解析Series.between(left, right, inclusive) 返回布尔 Series,表示值是否在指定区间内。inclusive 参数控制是否包含端点。

99. 使用 pd.get_dummies‘category’ 列进行独热编码(One-Hot Encoding)。

dummies = pd.get_dummies(df['category'], prefix='cat')
df_encoded = pd.concat([df, dummies], axis=1)
print(df_encoded.head())

解析:独热编码将分类变量转换为二进制(0/1)矩阵,是机器学习中处理分类特征的常用方法。prefix 参数为生成的列名添加前缀。

100. 将 DataFrame 导出为 JSON 格式文件 ‘data.json’,采用记录(records)格式。

df.to_json('data.json', orient='records')

解析df.to_json() 将 DataFrame 导出为 JSON 字符串或文件。orient=‘records’ 格式输出为记录列表,每行是一个 JSON 对象,这是与许多 Web API 交互的常用格式。


参考来源

 

更多推荐