Skip to content

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                  # 时间加法