前言

Pandas是Python中最强大的数据处理库之一,提供了丰富的功能来处理和分析各种类型的数据。本文将详细介绍Pandas的基本操作,包括数据结构、数据读取、数据处理、数据分析等方面的内容,帮助您快速掌握Pandas的核心功能。

核心数据结构

Pandas的主要数据结构是Series(一维数据)与DataFrame(二维数据),这两种数据结构足以处理金融、统计、社会科学、工程等领域里的大多数典型用例。

1. Series

Series是一种类似一维数组的对象,它由一组数据以及一组与之相关的数据标签(即索引)组成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd
import numpy as np

# 创建Series
# 从列表创建
s = pd.Series([1, 3, 5, np.nan, 6, 8])
print(s)

# 从字典创建
data = {'a': 1, 'b': 2, 'c': 3}
s = pd.Series(data)
print(s)

# 指定索引
s = pd.Series([1, 2, 3], index=['x', 'y', 'z'])
print(s)

2. DataFrame

DataFrame是一个表格型数据结构,含有一组有序的列,每一列可以是不同的类型值。DataFrame可以看成是由多个Series组成的字典,它们共用一个索引。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 创建DataFrame
# 从字典创建
data = {
'name': ['Alice', 'Bob', 'Charlie'],
'age': [25, 30, 35],
'city': ['New York', 'London', 'Paris']
}
df = pd.DataFrame(data)
print(df)

# 从列表创建
data = [[1, 'Alice', 25], [2, 'Bob', 30], [3, 'Charlie', 35]]
df = pd.DataFrame(data, columns=['id', 'name', 'age'])
print(df)

# 从NumPy数组创建
data = np.random.randn(5, 3)
df = pd.DataFrame(data, columns=['A', 'B', 'C'])
print(df)

数据读取与写入

1. 读取Excel文件

1
2
3
4
5
6
7
8
# 读取Excel文件
df = pd.read_excel('data.xlsx')

# 读取指定工作表
df = pd.read_excel('data.xlsx', sheet_name='Sheet1')

# 读取多个工作表
dfs = pd.read_excel('data.xlsx', sheet_name=['Sheet1', 'Sheet2'])

2. 读取CSV文件

1
2
3
4
5
6
7
8
# 读取CSV文件
df = pd.read_csv('data.csv')

# 自定义分隔符
df = pd.read_csv('data.tsv', sep='\t')

# 处理中文编码
df = pd.read_csv('data.csv', encoding='utf-8-sig')

3. 写入文件

1
2
3
4
5
# 写入Excel文件
df.to_excel('output.xlsx', index=False)

# 写入CSV文件
df.to_csv('output.csv', index=False, encoding='utf-8-sig')

数据查看与检查

1. 基本信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 查看前几行
print(df.head())
print(df.head(10)) # 查看前10行

# 查看后几行
print(df.tail())

# 查看数据形状(行数和列数)
print(df.shape)

# 查看数据类型
print(df.dtypes)

# 查看基本信息
print(df.info())

# 查看数值型列的统计信息
print(df.describe())

2. 索引与列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查看索引
print(df.index)

# 查看列名
print(df.columns)

# 查看值
print(df.values)

# 重命名列
df.columns = ['col1', 'col2', 'col3']

# 重新设置索引
df = df.set_index('col1')

# 重置索引
df = df.reset_index()

数据选择与过滤

1. 基于标签的选择(loc)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 选择行
df.loc[0] # 选择第一行
df.loc[0:2] # 选择前3行
df.loc[[0, 2, 4]] # 选择指定行

# 选择列
df.loc[:, 'name'] # 选择name列
df.loc[:, ['name', 'age']] # 选择name和age列

# 选择行和列
df.loc[0:2, ['name', 'age']] # 选择前3行的name和age列

# 条件选择
df.loc[df['age'] > 30] # 选择age大于30的行
df.loc[(df['age'] > 25) & (df['city'] == 'New York')] # 复合条件

2. 基于位置的选择(iloc)

1
2
3
4
5
6
7
8
9
10
11
# 选择行
df.iloc[0] # 选择第一行
df.iloc[0:3] # 选择前3行
df.iloc[[0, 2, 4]] # 选择指定行

# 选择列
df.iloc[:, 0] # 选择第一列
df.iloc[:, [0, 2]] # 选择第一和第三列

# 选择行和列
df.iloc[0:3, [0, 2]] # 选择前3行的第一和第三列

3. 快速选择

1
2
3
4
5
6
7
8
9
10
# 选择列
df['name'] # 选择name列
df.name # 选择name列(属性方式)
df[['name', 'age']] # 选择多列

# 选择行
df[0:3] # 选择前3行(基于位置)

# 条件选择
df[df['age'] > 30] # 选择age大于30的行

数据处理

1. 缺失值处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 检查缺失值
print(df.isnull()) # 检查每个元素是否为缺失值
print(df.isnull().sum()) # 统计每列的缺失值数量

# 删除缺失值
df.dropna() # 删除含有缺失值的行
df.dropna(axis=1) # 删除含有缺失值的列
df.dropna(how='all') # 只删除全为缺失值的行
df.dropna(thresh=2) # 删除缺失值数量超过2的行

# 填充缺失值
df.fillna(0) # 用0填充缺失值
df.fillna({'age': 25, 'city': 'Unknown'}) # 按列填充不同的值
df.fillna(method='ffill') # 用前一个值填充
df.fillna(method='bfill') # 用后一个值填充
df.fillna(df.mean()) # 用均值填充

2. 重复值处理

1
2
3
4
5
6
7
8
# 检查重复值
print(df.duplicated()) # 检查每行是否为重复行
print(df.duplicated().sum()) # 统计重复行数量

# 删除重复值
df.drop_duplicates() # 删除重复行,保留第一次出现的
df.drop_duplicates(keep='last') # 删除重复行,保留最后一次出现的
df.drop_duplicates(subset=['name', 'age']) # 基于指定列检查重复

3. 数据类型转换

1
2
3
4
5
6
7
8
9
10
11
# 查看数据类型
print(df.dtypes)

# 转换数据类型
df['age'] = df['age'].astype(int) # 转换为整型
df['salary'] = df['salary'].astype(float) # 转换为浮点型
df['date'] = pd.to_datetime(df['date']) # 转换为日期时间型
df['category'] = df['category'].astype('category') # 转换为分类型

# 转换整个DataFrame的数据类型
df = df.astype({'age': int, 'salary': float})

4. 数据替换

1
2
3
4
5
6
7
# 替换值
df.replace(0, np.nan) # 用NaN替换0
df.replace({'male': 0, 'female': 1}) # 替换多个值
df.replace('\s+', np.nan, regex=True) # 使用正则表达式替换

# 替换缺失值
df.replace(np.nan, 0) # 用0替换NaN

数据操作

1. 列操作

1
2
3
4
5
6
7
8
9
10
11
12
13
# 添加列
df['new_column'] = 0 # 添加新列并赋值为0
df['new_column'] = df['age'] * 2 # 基于现有列计算

# 删除列
df.drop('column_name', axis=1) # 删除指定列
df.drop(['col1', 'col2'], axis=1) # 删除多列

# 重命名列
df.rename(columns={'old_name': 'new_name'}) # 重命名列

# 重新排列列
df = df[['col3', 'col1', 'col2']] # 按指定顺序排列列

2. 行操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 添加行
df.loc[len(df)] = [1, 'Alice', 25] # 添加新行

# 删除行
df.drop(0) # 删除索引为0的行
df.drop([0, 1, 2]) # 删除多个行

# 排序
df.sort_values('age') # 按age列升序排序
df.sort_values('age', ascending=False) # 按age列降序排序
df.sort_values(['age', 'name']) # 按多列排序

# 重置索引
df = df.reset_index(drop=True) # 重置索引并删除旧索引

3. 数据计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 基本统计
df['age'].sum() # 求和
df['age'].mean() # 均值
df['age'].median() # 中位数
df['age'].min() # 最小值
df['age'].max() # 最大值
df['age'].std() # 标准差

# 分组统计
df.groupby('city')['age'].mean() # 按城市分组计算平均年龄
df.groupby('city').agg({'age': 'mean', 'salary': 'sum'}) # 多列聚合

# 透视表
df.pivot_table(values='salary', index='city', columns='department', aggfunc='mean')

# 交叉表
pd.crosstab(df['city'], df['department'])

高级功能

1. Apply函数

1
2
3
4
5
6
7
8
9
10
11
12
# 对Series应用函数
df['age'].apply(lambda x: x * 2) # 对age列的每个元素乘以2

# 对DataFrame应用函数
df.apply(lambda x: x.max() - x.min()) # 计算每列的范围

def custom_function(row):
return row['age'] * 2 + 1
df.apply(custom_function, axis=1) # 对每行应用自定义函数

# 应用多个函数
df['age'].apply([np.mean, np.median, np.std]) # 对age列应用多个统计函数

2. 字符串操作

1
2
3
4
5
6
7
8
9
# 字符串方法
df['name'].str.lower() # 转换为小写
df['name'].str.upper() # 转换为大写
df['name'].str.strip() # 去除首尾空格
df['name'].str.split(' ').str[0] # 分割字符串并取第一部分

# 字符串匹配
df[df['name'].str.contains('Alice')] # 选择name包含Alice的行
df[df['email'].str.match(r'^[\w\.-]+@[\w\.-]+\.\w+$')] # 使用正则表达式匹配邮箱

3. 时间序列处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 创建时间序列
dates = pd.date_range('2023-01-01', periods=365, freq='D')

# 时间索引
df = pd.DataFrame({'value': range(365)}, index=dates)

# 时间操作
df.index.year # 获取年份
df.index.month # 获取月份
df.index.day # 获取日期
df.index.weekday # 获取星期几

# 重采样
df.resample('M').mean() # 按月重采样计算均值
df.resample('Q').sum() # 按季度重采样计算总和

# 时间偏移
df.shift(1) # 数据向后偏移1天
df.shift(-1) # 数据向前偏移1天

4. 数据合并

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#  concat
df1 = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
df2 = pd.DataFrame({'A': [4, 5, 6], 'B': [7, 8, 9]})
pd.concat([df1, df2]) # 纵向合并

# merge
df1 = pd.DataFrame({'key': ['A', 'B', 'C'], 'value': [1, 2, 3]})
df2 = pd.DataFrame({'key': ['B', 'C', 'D'], 'value': [4, 5, 6]})
pd.merge(df1, df2, on='key') # 基于key列合并

# join
df1 = pd.DataFrame({'value1': [1, 2, 3]}, index=['A', 'B', 'C'])
df2 = pd.DataFrame({'value2': [4, 5, 6]}, index=['B', 'C', 'D'])
df1.join(df2) # 基于索引合并

性能优化

1. 内存优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看内存使用情况
print(df.info(memory_usage='deep'))

# 优化数据类型
df['age'] = df['age'].astype('int8') # 使用更小的整数类型
df['category'] = df['category'].astype('category') # 使用分类类型

# 选择需要的列
df = df[['name', 'age', 'salary']] # 只保留需要的列

# 分块处理大文件
chunksize = 10000
for chunk in pd.read_csv('large_file.csv', chunksize=chunksize):
# 处理每个块
pass

2. 速度优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 使用向量化操作
# 慢
for i in range(len(df)):
df.loc[i, 'new_column'] = df.loc[i, 'col1'] + df.loc[i, 'col2']

# 快
df['new_column'] = df['col1'] + df['col2']

# 使用内置函数
# 慢
import math
df['sqrt_col'] = df['col'].apply(math.sqrt)

# 快
df['sqrt_col'] = np.sqrt(df['col'])

# 使用query方法进行过滤
# 慢
df[df['age'] > 30 & df['salary'] > 50000]

# 快
df.query('age > 30 & salary > 50000')

实际应用示例

示例1:数据清洗与预处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import pandas as pd
import numpy as np

# 读取数据
df = pd.read_csv('raw_data.csv')

# 数据清洗
# 1. 处理缺失值
df = df.dropna(subset=['age', 'salary']) # 删除关键列有缺失值的行
df['city'] = df['city'].fillna('Unknown') # 填充城市列的缺失值

# 2. 处理重复值
df = df.drop_duplicates()

# 3. 处理异常值
df = df[df['salary'] > 0] # 过滤掉薪资为负数的行
df = df[df['age'] < 100] # 过滤掉年龄异常大的行

# 4. 数据转换
df['salary'] = df['salary'].astype(float)
df['hire_date'] = pd.to_datetime(df['hire_date'])

# 5. 特征工程
df['years_worked'] = 2023 - df['hire_date'].dt.year
df['salary_category'] = pd.cut(df['salary'], bins=[0, 30000, 60000, 100000], labels=['Low', 'Medium', 'High'])

# 保存处理后的数据
df.to_csv('processed_data.csv', index=False)
print("数据清洗完成!")

示例2:数据分析与可视化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# 读取数据
df = pd.read_csv('sales_data.csv')

# 数据探索
print(df.head())
print(df.info())
print(df.describe())

# 销售趋势分析
df['date'] = pd.to_datetime(df['date'])
df['month'] = df['date'].dt.month
monthly_sales = df.groupby('month')['sales'].sum()

# 可视化
plt.figure(figsize=(10, 6))
monthly_sales.plot(kind='bar')
plt.title('Monthly Sales')
plt.xlabel('Month')
plt.ylabel('Sales')
plt.show()

# 产品类别分析
category_sales = df.groupby('category')['sales'].sum().sort_values(ascending=False)

plt.figure(figsize=(10, 6))
category_sales.plot(kind='pie', autopct='%1.1f%%')
plt.title('Sales by Category')
plt.ylabel('')
plt.show()

# 客户分析
customer_sales = df.groupby('customer_id')['sales'].sum().sort_values(ascending=False)
top_10_customers = customer_sales.head(10)

plt.figure(figsize=(12, 6))
top_10_customers.plot(kind='bar')
plt.title('Top 10 Customers by Sales')
plt.xlabel('Customer ID')
plt.ylabel('Sales')
plt.xticks(rotation=45)
plt.show()

示例3:机器学习数据准备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline

# 读取数据
df = pd.read_csv('titanic.csv')

# 特征选择
features = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']
target = 'Survived'

X = df[features]
y = df[target]

# 数据预处理
# 处理缺失值
X['Age'] = X['Age'].fillna(X['Age'].median())
X['Embarked'] = X['Embarked'].fillna(X['Embarked'].mode()[0])

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 特征工程
numeric_features = ['Age', 'SibSp', 'Parch', 'Fare']
categorical_features = ['Pclass', 'Sex', 'Embarked']

preprocessor = ColumnTransformer(
transformers=[
('num', StandardScaler(), numeric_features),
('cat', OneHotEncoder(), categorical_features)
]
)

# 创建 pipeline
pipeline = Pipeline(steps=[('preprocessor', preprocessor)])

# 转换数据
X_train_transformed = pipeline.fit_transform(X_train)
X_test_transformed = pipeline.transform(X_test)

print("数据准备完成!")
print(f"训练集形状: {X_train_transformed.shape}")
print(f"测试集形状: {X_test_transformed.shape}")

常见问题与解决方案

1. 内存不足

问题:处理大型数据集时出现内存不足错误
解决方案

  • 使用分块读取:pd.read_csv('large_file.csv', chunksize=10000)
  • 选择需要的列:pd.read_csv('large_file.csv', usecols=['col1', 'col2']
  • 优化数据类型:df['col'] = df['col'].astype('int8')
  • 使用Dask库处理超大型数据集

2. 数据类型错误

问题:数据类型不匹配导致操作失败
解决方案

  • 检查数据类型:df.dtypes
  • 转换数据类型:df['col'] = df['col'].astype(float)
  • 处理日期时间:df['date'] = pd.to_datetime(df['date'])

3. 缺失值处理

问题:缺失值导致计算错误
解决方案

  • 检查缺失值:df.isnull().sum()
  • 删除缺失值:df.dropna()
  • 填充缺失值:df.fillna(value)

4. 性能问题

问题:代码执行速度慢
解决方案

  • 使用向量化操作:df['new_col'] = df['col1'] + df['col2']
  • 避免使用循环:使用apply或内置函数
  • 使用query方法进行过滤:df.query('condition')
  • 对大型DataFrame使用copy=False参数

5. 合并数据

问题:合并数据时出现重复列或键不匹配
解决方案

  • 确保合并键存在且类型匹配
  • 使用on参数指定合并键
  • 使用suffixes参数处理重复列名
  • 检查合并后的结果是否符合预期

总结

Pandas是一个功能强大的数据处理库,掌握其基本操作对于数据分析和数据科学工作至关重要。本文介绍了Pandas的核心功能,包括数据结构、数据读取、数据处理、数据分析等方面的内容,希望能帮助您快速上手Pandas。

在实际应用中,建议根据具体场景选择合适的方法和技巧,以获得最佳的性能和结果。同时,不断学习和探索Pandas的高级功能,可以让您的数据处理工作更加高效和便捷。

参考资料