Appearance
Pandas 面试题
1. Pandas 基础
问题:Pandas 的核心数据结构是什么?它们有什么区别?
答案:
核心数据结构:
- Series:一维带标签数组
- DataFrame:二维带标签数据结构
python
import pandas as pd
import numpy as np
# 1. Series
s = pd.Series([1, 3, 5, np.nan, 6, 8])
print(s)
# 0 1.0
# 1 3.0
# 2 5.0
# 3 NaN
# 4 6.0
# 5 8.0
# 带索引的 Series
s = pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])
# 2. DataFrame
df = pd.DataFrame({
'A': [1, 2, 3, 4],
'B': ['a', 'b', 'c', 'd'],
'C': [1.0, 2.0, 3.0, 4.0]
})
# 从字典创建
data = {
'name': ['Alice', 'Bob', 'Charlie'],
'age': [25, 30, 35],
'city': ['Beijing', 'Shanghai', 'Guangzhou']
}
df = pd.DataFrame(data)
# 从 NumPy 数组创建
df = pd.DataFrame(
np.random.randn(6, 4),
index=pd.date_range('20230101', periods=6),
columns=list('ABCD')
)2. 数据读取与保存
问题:Pandas 如何读写各种格式的数据?
答案:
python
import pandas as pd
# 1. CSV
df = pd.read_csv('data.csv')
df = pd.read_csv('data.csv', encoding='utf-8', sep=',')
df.to_csv('output.csv', index=False, encoding='utf-8')
# 2. Excel
df = pd.read_excel('data.xlsx', sheet_name='Sheet1')
df.to_excel('output.xlsx', sheet_name='Sheet1', index=False)
# 读取多个 sheet
xls = pd.ExcelFile('data.xlsx')
df1 = pd.read_excel(xls, 'Sheet1')
df2 = pd.read_excel(xls, 'Sheet2')
# 3. SQL
from sqlalchemy import create_engine
engine = create_engine('sqlite:///database.db')
df = pd.read_sql('SELECT * FROM table_name', engine)
df.to_sql('table_name', engine, if_exists='replace', index=False)
# 4. JSON
df = pd.read_json('data.json')
df.to_json('output.json', orient='records')
# 5. HDF5
df.to_hdf('data.h5', key='df', mode='w')
df = pd.read_hdf('data.h5', 'df')
# 6. 剪贴板
df = pd.read_clipboard()
df.to_clipboard(index=False)3. 数据选择与过滤
问题:如何在 Pandas 中选择和过滤数据?
答案:
python
import pandas as pd
import numpy as np
df = pd.DataFrame({
'A': [1, 2, 3, 4, 5],
'B': ['a', 'b', 'c', 'd', 'e'],
'C': [1.0, 2.0, 3.0, 4.0, 5.0]
}, index=['row1', 'row2', 'row3', 'row4', 'row5'])
# 1. 选择列
df['A'] # 单列(Series)
df[['A', 'B']] # 多列(DataFrame)
df.A # 点符号访问
# 2. loc(标签索引)
df.loc['row1'] # 单行
df.loc[:, 'A'] # 单列
df.loc['row1', 'A'] # 单个元素
df.loc['row1':'row3', ['A', 'B']] # 切片
# 3. iloc(位置索引)
df.iloc[0] # 第一行
df.iloc[:, 0] # 第一列
df.iloc[0, 0] # 第一个元素
df.iloc[0:3, 0:2] # 切片
# 4. 条件过滤
df[df['A'] > 2] # 单条件
df[(df['A'] > 2) & (df['C'] < 5)] # 多条件(与)
df[(df['A'] > 2) | (df['C'] < 2)] # 多条件(或)
df[df['B'].isin(['a', 'b'])] # 包含
# 5. query 方法
df.query('A > 2 and C < 5')
df.query('B in ["a", "b"]')
# 6. 布尔索引
mask = df['A'] > 2
df[mask]
# 7. where 方法
df.where(df > 2, other=0) # 不满足条件的置为0
# 8. isin 方法
df[df['B'].isin(['a', 'c'])]
df[~df['B'].isin(['a', 'c'])] # 不在列表中4. 数据处理与清洗
问题:如何使用 Pandas 进行数据清洗?
答案:
python
import pandas as pd
import numpy as np
df = pd.DataFrame({
'A': [1, 2, np.nan, 4, 5],
'B': ['a', 'b', 'c', None, 'e'],
'C': [1, 1, 2, 2, 3]
})
# 1. 处理缺失值
# 检查缺失值
df.isnull() # 检查缺失值
df.isnull().sum() # 每列缺失值数量
df.dropna() # 删除包含缺失值的行
df.dropna(axis=1) # 删除包含缺失值的列
df.dropna(how='all') # 删除全为缺失值的行
# 填充缺失值
df.fillna(0) # 用0填充
df.fillna(method='ffill') # 向前填充
df.fillna(method='bfill') # 向后填充
df['A'].fillna(df['A'].mean()) # 用均值填充
# 2. 删除重复值
df.drop_duplicates() # 删除完全重复的行
df.drop_duplicates(subset=['A']) # 基于某列删除重复
df.drop_duplicates(keep='last') # 保留最后一个
# 3. 数据类型转换
df['A'].astype(int) # 转为整数
df['A'].astype(float) # 转为浮点数
df['B'].astype(str) # 转为字符串
pd.to_numeric(df['A']) # 转为数值
df['date'] = pd.to_datetime(df['date']) # 转为日期
# 4. 数据替换
df['B'].replace('a', 'A') # 单值替换
df['B'].replace({'a': 'A', 'b': 'B'}) # 多值替换
df.replace(np.nan, 0) # 替换所有缺失值
# 5. 重命名
df.rename(columns={'A': 'Column_A', 'B': 'Column_B'})
df.rename(index={0: 'first', 1: 'second'})
# 6. 排序
df.sort_values('A') # 按列排序
df.sort_values(['A', 'B'], ascending=[True, False]) # 多列排序
df.sort_index() # 按索引排序
# 7. 应用函数
df['A'].apply(lambda x: x ** 2) # 应用函数
df.apply(np.sum, axis=0) # 按列应用
df.applymap(str) # 对所有元素应用
# 8. 字符串处理
df['B'].str.lower() # 转小写
df['B'].str.upper() # 转大写
df['B'].str.contains('a') # 包含
df['B'].str.replace('a', 'A') # 替换
df['B'].str.split(',') # 分割
df['B'].str.strip() # 去空白5. 数据聚合与分组
问题:如何使用 groupby 进行数据聚合?
答案:
python
import pandas as pd
import numpy as np
df = pd.DataFrame({
'A': ['foo', 'bar', 'foo', 'bar', 'foo', 'bar'],
'B': ['one', 'one', 'two', 'two', 'one', 'two'],
'C': np.random.randn(6),
'D': np.random.randn(6)
})
# 1. 基本分组
grouped = df.groupby('A')
grouped.mean() # 计算均值
grouped.sum() # 计算总和
grouped.count() # 计数
grouped.agg(['mean', 'sum', 'count']) # 多聚合
# 2. 多列分组
df.groupby(['A', 'B']).sum()
# 3. 自定义聚合
df.groupby('A').agg({
'C': 'sum',
'D': ['mean', 'std']
})
# 4. 自定义函数
df.groupby('A').agg(lambda x: x.max() - x.min())
# 5. transform(保持原索引)
df['C_mean'] = df.groupby('A')['C'].transform('mean')
# 6. filter(过滤组)
df.groupby('A').filter(lambda x: x['C'].sum() > 0)
# 7. apply(应用自定义函数)
def normalize(x):
return (x - x.mean()) / x.std()
df.groupby('A')['C'].apply(normalize)
# 8. 透视表
pd.pivot_table(df, values='D', index='A', columns='B', aggfunc='mean')
# 9. 交叉表
pd.crosstab(df['A'], df['B'])
# 10. resample(时间序列)
df['date'] = pd.date_range('20230101', periods=6)
df.set_index('date', inplace=True)
df.resample('M').mean() # 按月重采样6. 数据合并与连接
问题:Pandas 如何合并多个数据集?
答案:
python
import pandas as pd
df1 = pd.DataFrame({
'key': ['A', 'B', 'C', 'D'],
'value1': [1, 2, 3, 4]
})
df2 = pd.DataFrame({
'key': ['B', 'D', 'E', 'F'],
'value2': [5, 6, 7, 8]
})
# 1. merge(类似 SQL JOIN)
# 内连接(默认)
pd.merge(df1, df2, on='key')
# 左连接
pd.merge(df1, df2, on='key', how='left')
# 右连接
pd.merge(df1, df2, on='key', how='right')
# 外连接
pd.merge(df1, df2, on='key', how='outer')
# 多键连接
pd.merge(df1, df2, on=['key1', 'key2'])
# 不同列名连接
pd.merge(df1, df2, left_on='lkey', right_on='rkey')
# 2. join(基于索引)
df1.set_index('key', inplace=True)
df2.set_index('key', inplace=True)
df1.join(df2, how='outer')
# 3. concat(拼接)
# 纵向拼接(默认 axis=0)
pd.concat([df1, df2])
# 横向拼接
pd.concat([df1, df2], axis=1)
# 忽略索引
pd.concat([df1, df2], ignore_index=True)
# 添加层级索引
pd.concat([df1, df2], keys=['x', 'y'])
# 4. append(添加行)
df1.append(df2, ignore_index=True)
# 5. combine_first(填充缺失值)
df1.combine_first(df2)7. 时间序列处理
问题:Pandas 如何处理时间序列数据?
答案:
python
import pandas as pd
import numpy as np
# 1. 创建时间序列
dates = pd.date_range('20230101', periods=6, freq='D')
ts = pd.Series(np.random.randn(6), index=dates)
# 2. 时间戳转换
pd.to_datetime('2023-01-01')
pd.to_datetime(['2023-01-01', '2023-01-02'])
pd.to_datetime(1672531200, unit='s') # 从时间戳
# 3. 时间范围
dates = pd.date_range('20230101', '20231231', freq='M') # 月末
dates = pd.date_range('20230101', periods=12, freq='MS') # 月初
dates = pd.date_range('20230101', periods=10, freq='H') # 每小时
# 4. 重采样
ts.resample('M').mean() # 月均值
ts.resample('W').sum() # 周总和
ts.resample('Q').last() # 季度最后一个值
# 5. 移动窗口
ts.rolling(window=3).mean() # 移动平均
ts.rolling(window=3).std() # 移动标准差
ts.expanding().mean() # 扩展窗口平均
# 6. 时间偏移
ts.shift(1) # 向前移动1期
ts.shift(-1) # 向后移动1期
ts.shift(1, freq='D') # 按日期偏移
# 7. 时区处理
ts_utc = ts.tz_localize('UTC')
ts_shanghai = ts_utc.tz_convert('Asia/Shanghai')
# 8. 时间属性
ts.index.year # 年份
ts.index.month # 月份
ts.index.day # 日期
ts.index.dayofweek # 星期几
ts.index.is_month_end # 是否月末
# 9. 时间段
period = pd.Period('2023-01', freq='M')
period.start_time # 开始时间
period.end_time # 结束时间
# 10. 时间差
delta = pd.Timedelta(days=1, hours=2)
ts + delta # 时间加法