Python数据处理和分析库
NumPy
NumPy简介
NumPy(Numerical Python)是Python中用于科学计算的基础包,它提供了:
- 强大的N维数组对象
- 广播功能
- 线性代数、傅里叶变换和随机数生成等功能
- 与C/C++和Fortran代码集成的工具
NumPy是许多Python科学计算库的基础,如Pandas、SciPy、Matplotlib等。
安装NumPy
bash
pip install numpypip install numpyNumPy数组(ndarray)
NumPy的核心是ndarray对象,它是一个同构的多维数组,所有元素必须是相同类型。
python
import numpy as np
# 创建一维数组
a = np.array([1, 2, 3, 4, 5])
print(a) # [1 2 3 4 5]
print(type(a)) # <class 'numpy.ndarray'>
# 创建二维数组
b = np.array([[1, 2, 3], [4, 5, 6]])
print(b) # [[1 2 3]
# [4 5 6]]
# 数组的属性
print(a.shape) # (5,) - 一维数组,5个元素
print(b.shape) # (2, 3) - 二维数组,2行3列
print(a.dtype) # int64 - 元素类型
print(a.ndim) # 1 - 数组维度
print(a.size) # 5 - 元素总数import numpy as np
# 创建一维数组
a = np.array([1, 2, 3, 4, 5])
print(a) # [1 2 3 4 5]
print(type(a)) # <class 'numpy.ndarray'>
# 创建二维数组
b = np.array([[1, 2, 3], [4, 5, 6]])
print(b) # [[1 2 3]
# [4 5 6]]
# 数组的属性
print(a.shape) # (5,) - 一维数组,5个元素
print(b.shape) # (2, 3) - 二维数组,2行3列
print(a.dtype) # int64 - 元素类型
print(a.ndim) # 1 - 数组维度
print(a.size) # 5 - 元素总数创建数组的方法
python
# 创建全零数组
zeros = np.zeros((2, 3))
print(zeros) # [[0. 0. 0.]
# [0. 0. 0.]]
# 创建全一数组
ones = np.ones((2, 3))
print(ones) # [[1. 1. 1.]
# [1. 1. 1.]]
# 创建指定值的数组
full = np.full((2, 3), 5)
print(full) # [[5 5 5]
# [5 5 5]]
# 创建单位矩阵
eye = np.eye(3)
print(eye) # [[1. 0. 0.]
# [0. 1. 0.]
# [0. 0. 1.]]
# 创建等差数列
arange = np.arange(0, 10, 2)
print(arange) # [0 2 4 6 8]
# 创建等间隔数列
linspace = np.linspace(0, 10, 5)
print(linspace) # [ 0. 2.5 5. 7.5 10. ]
# 创建随机数组
random = np.random.rand(2, 3) # 0-1之间的随机数
print(random) # [[0.123 0.456 0.789]
# [0.321 0.654 0.987]]
random_int = np.random.randint(0, 10, (2, 3)) # 0-10之间的随机整数
print(random_int) # [[1 2 3]
# [4 5 6]]# 创建全零数组
zeros = np.zeros((2, 3))
print(zeros) # [[0. 0. 0.]
# [0. 0. 0.]]
# 创建全一数组
ones = np.ones((2, 3))
print(ones) # [[1. 1. 1.]
# [1. 1. 1.]]
# 创建指定值的数组
full = np.full((2, 3), 5)
print(full) # [[5 5 5]
# [5 5 5]]
# 创建单位矩阵
eye = np.eye(3)
print(eye) # [[1. 0. 0.]
# [0. 1. 0.]
# [0. 0. 1.]]
# 创建等差数列
arange = np.arange(0, 10, 2)
print(arange) # [0 2 4 6 8]
# 创建等间隔数列
linspace = np.linspace(0, 10, 5)
print(linspace) # [ 0. 2.5 5. 7.5 10. ]
# 创建随机数组
random = np.random.rand(2, 3) # 0-1之间的随机数
print(random) # [[0.123 0.456 0.789]
# [0.321 0.654 0.987]]
random_int = np.random.randint(0, 10, (2, 3)) # 0-10之间的随机整数
print(random_int) # [[1 2 3]
# [4 5 6]]数组索引和切片
python
# 一维数组索引和切片
arr = np.array([0, 1, 2, 3, 4, 5])
print(arr[0]) # 0
print(arr[-1]) # 5
print(arr[1:4]) # [1 2 3]
print(arr[::2]) # [0 2 4]
# 二维数组索引和切片
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr2d[0, 0]) # 1
print(arr2d[1, 2]) # 6
print(arr2d[:, 0]) # [1 4 7] - 第一列
print(arr2d[0, :]) # [1 2 3] - 第一行
print(arr2d[0:2, 1:3]) # [[2 3]
# [5 6]] - 前两行,后两列# 一维数组索引和切片
arr = np.array([0, 1, 2, 3, 4, 5])
print(arr[0]) # 0
print(arr[-1]) # 5
print(arr[1:4]) # [1 2 3]
print(arr[::2]) # [0 2 4]
# 二维数组索引和切片
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr2d[0, 0]) # 1
print(arr2d[1, 2]) # 6
print(arr2d[:, 0]) # [1 4 7] - 第一列
print(arr2d[0, :]) # [1 2 3] - 第一行
print(arr2d[0:2, 1:3]) # [[2 3]
# [5 6]] - 前两行,后两列数组操作
python
# 数组形状变换
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.shape) # (2, 3)
# 转置
transposed = arr.T
print(transposed.shape) # (3, 2)
# 重塑
reshaped = arr.reshape(3, 2)
print(reshaped.shape) # (3, 2)
# 展平
flattened = arr.flatten()
print(flattened) # [1 2 3 4 5 6]
# 数组拼接
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
# 水平拼接
hstack = np.hstack((arr1, arr2))
print(hstack) # [[1 2 5 6]
# [3 4 7 8]]
# 垂直拼接
vstack = np.vstack((arr1, arr2))
print(vstack) # [[1 2]
# [3 4]
# [5 6]
# [7 8]]
# 数组分割
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
# 水平分割
hsplit = np.hsplit(arr, 2)
print(hsplit) # [array([[ 1, 2],
# [ 5, 6],
# [ 9, 10]]),
# array([[ 3, 4],
# [ 7, 8],
# [11, 12]])]
# 垂直分割
vsplit = np.vsplit(arr, 3)
print(vsplit) # [array([[1, 2, 3, 4]]), array([[5, 6, 7, 8]]), array([[ 9, 10, 11, 12]])]# 数组形状变换
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.shape) # (2, 3)
# 转置
transposed = arr.T
print(transposed.shape) # (3, 2)
# 重塑
reshaped = arr.reshape(3, 2)
print(reshaped.shape) # (3, 2)
# 展平
flattened = arr.flatten()
print(flattened) # [1 2 3 4 5 6]
# 数组拼接
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
# 水平拼接
hstack = np.hstack((arr1, arr2))
print(hstack) # [[1 2 5 6]
# [3 4 7 8]]
# 垂直拼接
vstack = np.vstack((arr1, arr2))
print(vstack) # [[1 2]
# [3 4]
# [5 6]
# [7 8]]
# 数组分割
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
# 水平分割
hsplit = np.hsplit(arr, 2)
print(hsplit) # [array([[ 1, 2],
# [ 5, 6],
# [ 9, 10]]),
# array([[ 3, 4],
# [ 7, 8],
# [11, 12]])]
# 垂直分割
vsplit = np.vsplit(arr, 3)
print(vsplit) # [array([[1, 2, 3, 4]]), array([[5, 6, 7, 8]]), array([[ 9, 10, 11, 12]])]数组运算
python
# 基本运算
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
print(arr1 + arr2) # [5 7 9]
print(arr1 - arr2) # [-3 -3 -3]
print(arr1 * arr2) # [4 10 18]
print(arr1 / arr2) # [0.25 0.4 0.5 ]
print(arr1 ** 2) # [1 4 9]
# 广播
arr3 = np.array([[1, 2, 3], [4, 5, 6]])
scalar = 2
print(arr3 + scalar) # [[3 4 5]
# [6 7 8]]
# 矩阵乘法
mat1 = np.array([[1, 2], [3, 4]])
mat2 = np.array([[5, 6], [7, 8]])
print(np.dot(mat1, mat2)) # [[19 22]
# [43 50]]
# 或者使用 @ 运算符
print(mat1 @ mat2) # 同上
# 元素级函数
arr = np.array([0, np.pi/2, np.pi])
print(np.sin(arr)) # [0.0000000e+00 1.0000000e+00 1.2246468e-16]
print(np.cos(arr)) # [ 1.000000e+00 6.123234e-17 -1.000000e+00]
print(np.exp(arr)) # [ 1. 4.81047738 23.14069263]
print(np.log(arr + 1)) # [0. 0.69314718 1.09861229]# 基本运算
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
print(arr1 + arr2) # [5 7 9]
print(arr1 - arr2) # [-3 -3 -3]
print(arr1 * arr2) # [4 10 18]
print(arr1 / arr2) # [0.25 0.4 0.5 ]
print(arr1 ** 2) # [1 4 9]
# 广播
arr3 = np.array([[1, 2, 3], [4, 5, 6]])
scalar = 2
print(arr3 + scalar) # [[3 4 5]
# [6 7 8]]
# 矩阵乘法
mat1 = np.array([[1, 2], [3, 4]])
mat2 = np.array([[5, 6], [7, 8]])
print(np.dot(mat1, mat2)) # [[19 22]
# [43 50]]
# 或者使用 @ 运算符
print(mat1 @ mat2) # 同上
# 元素级函数
arr = np.array([0, np.pi/2, np.pi])
print(np.sin(arr)) # [0.0000000e+00 1.0000000e+00 1.2246468e-16]
print(np.cos(arr)) # [ 1.000000e+00 6.123234e-17 -1.000000e+00]
print(np.exp(arr)) # [ 1. 4.81047738 23.14069263]
print(np.log(arr + 1)) # [0. 0.69314718 1.09861229]统计函数
python
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(np.min(arr)) # 1 - 最小值
print(np.max(arr)) # 9 - 最大值
print(np.mean(arr)) # 5.0 - 平均值
print(np.median(arr)) # 5.0 - 中位数
print(np.std(arr)) # 2.581988897471611 - 标准差
print(np.var(arr)) # 6.666666666666667 - 方差
print(np.sum(arr)) # 45 - 总和
# 按轴计算
print(np.sum(arr, axis=0)) # [12 15 18] - 按列求和
print(np.sum(arr, axis=1)) # [ 6 15 24] - 按行求和arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(np.min(arr)) # 1 - 最小值
print(np.max(arr)) # 9 - 最大值
print(np.mean(arr)) # 5.0 - 平均值
print(np.median(arr)) # 5.0 - 中位数
print(np.std(arr)) # 2.581988897471611 - 标准差
print(np.var(arr)) # 6.666666666666667 - 方差
print(np.sum(arr)) # 45 - 总和
# 按轴计算
print(np.sum(arr, axis=0)) # [12 15 18] - 按列求和
print(np.sum(arr, axis=1)) # [ 6 15 24] - 按行求和Pandas
Pandas简介
Pandas是一个强大的数据分析和处理库,提供了:
- 快速、灵活的数据结构(Series和DataFrame)
- 用于读取和写入数据的工具
- 数据清洗和预处理功能
- 数据聚合和分组操作
- 时间序列分析功能
Pandas是数据科学和机器学习中常用的库,特别适合处理结构化数据。
安装Pandas
bash
pip install pandaspip install pandasPandas的核心数据结构
Pandas有两种核心数据结构:
- Series:一维标记数组,类似于带索引的列表
- DataFrame:二维表格数据结构,由多个Series组成
Series
python
import pandas as pd
# 创建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
# dtype: float64
# 带有索引的Series
s2 = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
print(s2) # a 1
# b 2
# c 3
# dtype: int64
# 使用字典创建Series
s3 = pd.Series({'a': 1, 'b': 2, 'c': 3})
print(s3) # 同上
# Series的属性
print(s.index) # RangeIndex(start=0, stop=6, step=1)
print(s.values) # [ 1. 3. 5. nan 6. 8.]
print(s.dtype) # float64
# Series的索引和切片
print(s2['a']) # 1
print(s2[['a', 'c']]) # a 1
# c 3
# dtype: int64
print(s2[:2]) # a 1
# b 2
# dtype: int64import pandas as pd
# 创建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
# dtype: float64
# 带有索引的Series
s2 = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
print(s2) # a 1
# b 2
# c 3
# dtype: int64
# 使用字典创建Series
s3 = pd.Series({'a': 1, 'b': 2, 'c': 3})
print(s3) # 同上
# Series的属性
print(s.index) # RangeIndex(start=0, stop=6, step=1)
print(s.values) # [ 1. 3. 5. nan 6. 8.]
print(s.dtype) # float64
# Series的索引和切片
print(s2['a']) # 1
print(s2[['a', 'c']]) # a 1
# c 3
# dtype: int64
print(s2[:2]) # a 1
# b 2
# dtype: int64DataFrame
python
# 创建DataFrame
# 方法1:使用字典
data = {
'name': ['张三', '李四', '王五', '赵六'],
'age': [20, 25, 30, 35],
'city': ['北京', '上海', '广州', '深圳']
}
df = pd.DataFrame(data)
print(df)
# name age city
# 0 张三 20 北京
# 1 李四 25 上海
# 2 王五 30 广州
# 3 赵六 35 深圳
# 方法2:使用numpy数组
df2 = pd.DataFrame(np.random.rand(3, 4), columns=['a', 'b', 'c', 'd'])
print(df2)
# DataFrame的属性
print(df.shape) # (4, 3)
print(df.columns) # Index(['name', 'age', 'city'], dtype='object')
print(df.index) # RangeIndex(start=0, stop=4, step=1)
print(df.dtypes) # name object
# age int64
# city object
# dtype: object
# DataFrame的索引和切片
# 选择列
print(df['name']) # 选择name列,返回Series
print(df[['name', 'age']]) # 选择多列,返回DataFrame
# 选择行
print(df.loc[0]) # 选择第一行,返回Series
print(df.loc[[0, 2]]) # 选择多行,返回DataFrame
# 选择行和列
print(df.loc[0, 'name']) # 张三
print(df.loc[:, ['name', 'age']]) # 选择所有行和name、age列
print(df.loc[0:2, ['name', 'age']]) # 选择前3行和name、age列
# 使用iloc进行位置索引
print(df.iloc[0, 0]) # 张三
print(df.iloc[:, 0:2]) # 选择所有行和前2列
# 布尔索引
print(df[df['age'] > 25]) # 选择age大于25的行
print(df[(df['age'] > 20) & (df['city'] == '上海')]) # 选择age大于20且city为上海的行# 创建DataFrame
# 方法1:使用字典
data = {
'name': ['张三', '李四', '王五', '赵六'],
'age': [20, 25, 30, 35],
'city': ['北京', '上海', '广州', '深圳']
}
df = pd.DataFrame(data)
print(df)
# name age city
# 0 张三 20 北京
# 1 李四 25 上海
# 2 王五 30 广州
# 3 赵六 35 深圳
# 方法2:使用numpy数组
df2 = pd.DataFrame(np.random.rand(3, 4), columns=['a', 'b', 'c', 'd'])
print(df2)
# DataFrame的属性
print(df.shape) # (4, 3)
print(df.columns) # Index(['name', 'age', 'city'], dtype='object')
print(df.index) # RangeIndex(start=0, stop=4, step=1)
print(df.dtypes) # name object
# age int64
# city object
# dtype: object
# DataFrame的索引和切片
# 选择列
print(df['name']) # 选择name列,返回Series
print(df[['name', 'age']]) # 选择多列,返回DataFrame
# 选择行
print(df.loc[0]) # 选择第一行,返回Series
print(df.loc[[0, 2]]) # 选择多行,返回DataFrame
# 选择行和列
print(df.loc[0, 'name']) # 张三
print(df.loc[:, ['name', 'age']]) # 选择所有行和name、age列
print(df.loc[0:2, ['name', 'age']]) # 选择前3行和name、age列
# 使用iloc进行位置索引
print(df.iloc[0, 0]) # 张三
print(df.iloc[:, 0:2]) # 选择所有行和前2列
# 布尔索引
print(df[df['age'] > 25]) # 选择age大于25的行
print(df[(df['age'] > 20) & (df['city'] == '上海')]) # 选择age大于20且city为上海的行数据读取和写入
python
# 读取CSV文件
df = pd.read_csv('data.csv')
# 读取Excel文件
df = pd.read_excel('data.xlsx', sheet_name='Sheet1')
# 读取JSON文件
df = pd.read_json('data.json')
# 读取SQL数据库
import sqlite3
conn = sqlite3.connect('database.db')
df = pd.read_sql_query('SELECT * FROM table', conn)
# 写入CSV文件
df.to_csv('output.csv', index=False)
# 写入Excel文件
df.to_excel('output.xlsx', sheet_name='Sheet1', index=False)
# 写入JSON文件
df.to_json('output.json', orient='records')# 读取CSV文件
df = pd.read_csv('data.csv')
# 读取Excel文件
df = pd.read_excel('data.xlsx', sheet_name='Sheet1')
# 读取JSON文件
df = pd.read_json('data.json')
# 读取SQL数据库
import sqlite3
conn = sqlite3.connect('database.db')
df = pd.read_sql_query('SELECT * FROM table', conn)
# 写入CSV文件
df.to_csv('output.csv', index=False)
# 写入Excel文件
df.to_excel('output.xlsx', sheet_name='Sheet1', index=False)
# 写入JSON文件
df.to_json('output.json', orient='records')数据清洗和预处理
python
# 检查缺失值
print(df.isnull()) # 检查每个元素是否为缺失值
print(df.isnull().sum()) # 检查每列的缺失值数量
# 处理缺失值
# 删除缺失值
df.dropna() # 删除包含缺失值的行
df.dropna(axis=1) # 删除包含缺失值的列
# 填充缺失值
df.fillna(0) # 用0填充缺失值
df.fillna(method='ffill') # 向前填充
df.fillna(method='bfill') # 向后填充
df.fillna(df.mean()) # 用平均值填充
# 数据重复
# 检查重复行
print(df.duplicated()) # 检查每行是否重复
print(df.duplicated().sum()) # 重复行的数量
# 删除重复行
df.drop_duplicates() # 删除重复行
df.drop_duplicates(subset=['name'], keep='last') # 根据name列删除重复行,保留最后一行
# 数据类型转换
df['age'] = df['age'].astype(str) # 将age列转换为字符串类型
# 重命名列
df.rename(columns={'name': '姓名', 'age': '年龄'}, inplace=True)
# 重置索引
df.reset_index(drop=True, inplace=True)# 检查缺失值
print(df.isnull()) # 检查每个元素是否为缺失值
print(df.isnull().sum()) # 检查每列的缺失值数量
# 处理缺失值
# 删除缺失值
df.dropna() # 删除包含缺失值的行
df.dropna(axis=1) # 删除包含缺失值的列
# 填充缺失值
df.fillna(0) # 用0填充缺失值
df.fillna(method='ffill') # 向前填充
df.fillna(method='bfill') # 向后填充
df.fillna(df.mean()) # 用平均值填充
# 数据重复
# 检查重复行
print(df.duplicated()) # 检查每行是否重复
print(df.duplicated().sum()) # 重复行的数量
# 删除重复行
df.drop_duplicates() # 删除重复行
df.drop_duplicates(subset=['name'], keep='last') # 根据name列删除重复行,保留最后一行
# 数据类型转换
df['age'] = df['age'].astype(str) # 将age列转换为字符串类型
# 重命名列
df.rename(columns={'name': '姓名', 'age': '年龄'}, inplace=True)
# 重置索引
df.reset_index(drop=True, inplace=True)数据聚合和分组
python
# 基本统计
print(df.describe()) # 显示数值列的统计信息
print(df.mean()) # 计算平均值
print(df.median()) # 计算中位数
print(df.max()) # 计算最大值
print(df.min()) # 计算最小值
# 分组操作
grouped = df.groupby('city') # 按city列分组
print(grouped['age'].mean()) # 计算每个城市的平均年龄
print(grouped['age'].agg(['mean', 'sum', 'count'])) # 计算每个城市的平均年龄、总年龄和人数
# 多列分组
grouped = df.groupby(['city', 'gender'])
print(grouped['age'].mean())
# 透视表
pivot_table = df.pivot_table(index='city', columns='gender', values='age', aggfunc='mean')
print(pivot_table)# 基本统计
print(df.describe()) # 显示数值列的统计信息
print(df.mean()) # 计算平均值
print(df.median()) # 计算中位数
print(df.max()) # 计算最大值
print(df.min()) # 计算最小值
# 分组操作
grouped = df.groupby('city') # 按city列分组
print(grouped['age'].mean()) # 计算每个城市的平均年龄
print(grouped['age'].agg(['mean', 'sum', 'count'])) # 计算每个城市的平均年龄、总年龄和人数
# 多列分组
grouped = df.groupby(['city', 'gender'])
print(grouped['age'].mean())
# 透视表
pivot_table = df.pivot_table(index='city', columns='gender', values='age', aggfunc='mean')
print(pivot_table)数据合并和连接
python
# 创建两个DataFrame
df1 = pd.DataFrame({
'id': [1, 2, 3, 4],
'name': ['张三', '李四', '王五', '赵六'],
'city': ['北京', '上海', '广州', '深圳']
})
df2 = pd.DataFrame({
'id': [1, 2, 3, 5],
'age': [20, 25, 30, 35],
'gender': ['男', '女', '男', '女']
})
# 内连接(只保留匹配的行)
inner_join = pd.merge(df1, df2, on='id', how='inner')
print(inner_join)
# 左连接(保留左表的所有行)
left_join = pd.merge(df1, df2, on='id', how='left')
print(left_join)
# 右连接(保留右表的所有行)
right_join = pd.merge(df1, df2, on='id', how='right')
print(right_join)
# 外连接(保留所有行)
outer_join = pd.merge(df1, df2, on='id', how='outer')
print(outer_join)
# 追加行
df3 = pd.DataFrame({
'id': [6],
'name': ['钱七'],
'city': ['杭州']
})
appended = df1.append(df3, ignore_index=True)
print(appended)# 创建两个DataFrame
df1 = pd.DataFrame({
'id': [1, 2, 3, 4],
'name': ['张三', '李四', '王五', '赵六'],
'city': ['北京', '上海', '广州', '深圳']
})
df2 = pd.DataFrame({
'id': [1, 2, 3, 5],
'age': [20, 25, 30, 35],
'gender': ['男', '女', '男', '女']
})
# 内连接(只保留匹配的行)
inner_join = pd.merge(df1, df2, on='id', how='inner')
print(inner_join)
# 左连接(保留左表的所有行)
left_join = pd.merge(df1, df2, on='id', how='left')
print(left_join)
# 右连接(保留右表的所有行)
right_join = pd.merge(df1, df2, on='id', how='right')
print(right_join)
# 外连接(保留所有行)
outer_join = pd.merge(df1, df2, on='id', how='outer')
print(outer_join)
# 追加行
df3 = pd.DataFrame({
'id': [6],
'name': ['钱七'],
'city': ['杭州']
})
appended = df1.append(df3, ignore_index=True)
print(appended)时间序列分析
python
# 创建时间序列
dates = pd.date_range('2023-01-01', periods=7)
print(dates) # DatetimeIndex(['2023-01-01', '2023-01-02', '2023-01-03', '2023-01-04',
# '2023-01-05', '2023-01-06', '2023-01-07'],
# dtype='datetime64[ns]', freq='D')
# 创建带时间索引的DataFrame
df = pd.DataFrame(np.random.randn(7, 3), index=dates, columns=['a', 'b', 'c'])
print(df)
# 时间索引的使用
print(df.loc['2023-01-01']) # 选择2023-01-01的行
print(df.loc['2023-01-01':'2023-01-03']) # 选择2023-01-01到2023-01-03的行
print(df.loc['2023-01']) # 选择2023年1月的行
# 时间序列的频率转换
daily_df = pd.DataFrame(
{'value': np.random.randn(365)},
index=pd.date_range('2023-01-01', periods=365, freq='D')
)
# 转换为月度频率
monthly_df = daily_df.resample('M').mean()
print(monthly_df)
# 移动平均
daily_df['ma7'] = daily_df['value'].rolling(window=7).mean()
print(daily_df)# 创建时间序列
dates = pd.date_range('2023-01-01', periods=7)
print(dates) # DatetimeIndex(['2023-01-01', '2023-01-02', '2023-01-03', '2023-01-04',
# '2023-01-05', '2023-01-06', '2023-01-07'],
# dtype='datetime64[ns]', freq='D')
# 创建带时间索引的DataFrame
df = pd.DataFrame(np.random.randn(7, 3), index=dates, columns=['a', 'b', 'c'])
print(df)
# 时间索引的使用
print(df.loc['2023-01-01']) # 选择2023-01-01的行
print(df.loc['2023-01-01':'2023-01-03']) # 选择2023-01-01到2023-01-03的行
print(df.loc['2023-01']) # 选择2023年1月的行
# 时间序列的频率转换
daily_df = pd.DataFrame(
{'value': np.random.randn(365)},
index=pd.date_range('2023-01-01', periods=365, freq='D')
)
# 转换为月度频率
monthly_df = daily_df.resample('M').mean()
print(monthly_df)
# 移动平均
daily_df['ma7'] = daily_df['value'].rolling(window=7).mean()
print(daily_df)数据可视化
Matplotlib
Matplotlib是Python中最常用的数据可视化库,它提供了广泛的绘图功能。
bash
pip install matplotlibpip install matplotlibpython
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 折线图
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.plot(x, y)
plt.title('正弦函数')
plt.xlabel('x')
plt.ylabel('sin(x)')
plt.grid(True)
plt.show()
# 柱状图
data = {'A': 10, 'B': 15, 'C': 7, 'D': 12}
plt.bar(data.keys(), data.values())
plt.title('柱状图')
plt.xlabel('类别')
plt.ylabel('值')
plt.show()
# 散点图
x = np.random.rand(50)
y = np.random.rand(50)
colors = np.random.rand(50)
sizes = 1000 * np.random.rand(50)
plt.scatter(x, y, c=colors, s=sizes, alpha=0.5, cmap='viridis')
plt.colorbar()
plt.title('散点图')
plt.show()
# 使用pandas绘图
df = pd.DataFrame(np.random.rand(10, 4), columns=['a', 'b', 'c', 'd'])
df.plot.bar()
plt.title('DataFrame柱状图')
plt.show()
df.plot.line()
plt.title('DataFrame折线图')
plt.show()import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 折线图
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.plot(x, y)
plt.title('正弦函数')
plt.xlabel('x')
plt.ylabel('sin(x)')
plt.grid(True)
plt.show()
# 柱状图
data = {'A': 10, 'B': 15, 'C': 7, 'D': 12}
plt.bar(data.keys(), data.values())
plt.title('柱状图')
plt.xlabel('类别')
plt.ylabel('值')
plt.show()
# 散点图
x = np.random.rand(50)
y = np.random.rand(50)
colors = np.random.rand(50)
sizes = 1000 * np.random.rand(50)
plt.scatter(x, y, c=colors, s=sizes, alpha=0.5, cmap='viridis')
plt.colorbar()
plt.title('散点图')
plt.show()
# 使用pandas绘图
df = pd.DataFrame(np.random.rand(10, 4), columns=['a', 'b', 'c', 'd'])
df.plot.bar()
plt.title('DataFrame柱状图')
plt.show()
df.plot.line()
plt.title('DataFrame折线图')
plt.show()Seaborn
Seaborn是基于Matplotlib的高级数据可视化库,提供了更美观的默认样式和更高级的绘图功能。
bash
pip install seabornpip install seabornpython
import seaborn as sns
import numpy as np
import pandas as pd
# 加载示例数据
tips = sns.load_dataset('tips')
# 箱线图
sns.boxplot(x='day', y='total_bill', data=tips)
sns.despine(offset=10, trim=True)
plt.title('箱线图')
plt.show()
# 热力图
corr = np.corrcoef(np.random.randn(10, 200))
sns.heatmap(corr, vmax=.3, center=0, square=True, linewidths=.5, cbar_kws={"shrink": .5})
plt.title('热力图')
plt.show()
# 成对关系图
sns.pairplot(tips, hue="size")
plt.title('成对关系图')
plt.show()import seaborn as sns
import numpy as np
import pandas as pd
# 加载示例数据
tips = sns.load_dataset('tips')
# 箱线图
sns.boxplot(x='day', y='total_bill', data=tips)
sns.despine(offset=10, trim=True)
plt.title('箱线图')
plt.show()
# 热力图
corr = np.corrcoef(np.random.randn(10, 200))
sns.heatmap(corr, vmax=.3, center=0, square=True, linewidths=.5, cbar_kws={"shrink": .5})
plt.title('热力图')
plt.show()
# 成对关系图
sns.pairplot(tips, hue="size")
plt.title('成对关系图')
plt.show()Polars(高性能 DataFrame)
Polars 是一个 Rust 编写的 DataFrame 库,性能远超 Pandas(3-20 倍),2024-2025 年增长最快的 Python 数据处理库。
安装 Polars
bash
pip install polarspip install polars核心概念
- DataFrame / Series:与 Pandas 类似的数据结构
- Expr:表达式系统,Polars 的核心抽象,所有操作都是表达式
- Lazy / Eager API:惰性查询优化 vs 立即执行
- 无索引:Polars 没有 Pandas 的行索引概念,更简洁
基本使用
python
import polars as pl
# 创建 DataFrame
df = pl.DataFrame({
"name": ["张三", "李四", "王五", "赵六"],
"age": [20, 25, 30, 35],
"city": ["北京", "上海", "广州", "深圳"],
"salary": [10000, 15000, 20000, 25000],
})
print(df)
# shape: (4, 4)
# ┌──────┬─────┬──────┬────────┐
# │ name ┆ age ┆ city ┆ salary │
# │ --- ┆ --- ┆ --- ┆ --- │
# │ str ┆ i64 ┆ str ┆ i64 │
# ╞══════╪═════╪══════╪════════╡
# │ 张三 ┆ 20 ┆ 北京 ┆ 10000 │
# │ 李四 ┆ 25 ┆ 上海 ┆ 15000 │
# │ 王五 ┆ 30 ┆ 广州 ┆ 20000 │
# │ 赵六 ┆ 35 ┆ 深圳 ┆ 25000 │
# └──────┴─────┴──────┴────────┘
# 读取 CSV
df = pl.read_csv("data.csv")
# 读取 JSON
df = pl.read_json("data.json")
# 读取 Parquet(Polars 强项)
df = pl.read_parquet("data.parquet")import polars as pl
# 创建 DataFrame
df = pl.DataFrame({
"name": ["张三", "李四", "王五", "赵六"],
"age": [20, 25, 30, 35],
"city": ["北京", "上海", "广州", "深圳"],
"salary": [10000, 15000, 20000, 25000],
})
print(df)
# shape: (4, 4)
# ┌──────┬─────┬──────┬────────┐
# │ name ┆ age ┆ city ┆ salary │
# │ --- ┆ --- ┆ --- ┆ --- │
# │ str ┆ i64 ┆ str ┆ i64 │
# ╞══════╪═════╪══════╪════════╡
# │ 张三 ┆ 20 ┆ 北京 ┆ 10000 │
# │ 李四 ┆ 25 ┆ 上海 ┆ 15000 │
# │ 王五 ┆ 30 ┆ 广州 ┆ 20000 │
# │ 赵六 ┆ 35 ┆ 深圳 ┆ 25000 │
# └──────┴─────┴──────┴────────┘
# 读取 CSV
df = pl.read_csv("data.csv")
# 读取 JSON
df = pl.read_json("data.json")
# 读取 Parquet(Polars 强项)
df = pl.read_parquet("data.parquet")数据操作(Polars 风格)
python
# 选择列
df.select("name", "salary")
# 使用表达式
df.select([
pl.col("name"),
pl.col("salary") / 10000, # 列运算
])
# 过滤
df.filter(pl.col("age") > 25)
df.filter(pl.col("city").is_in(["北京", "上海"]))
# 添加/修改列
df.with_columns(
(pl.col("salary") * 1.1).alias("salary_after_raise")
)
# 分组聚合
df.group_by("city").agg([
pl.col("salary").mean().alias("avg_salary"),
pl.col("age").max().alias("max_age"),
pl.len().alias("count"), # 行数
])# 选择列
df.select("name", "salary")
# 使用表达式
df.select([
pl.col("name"),
pl.col("salary") / 10000, # 列运算
])
# 过滤
df.filter(pl.col("age") > 25)
df.filter(pl.col("city").is_in(["北京", "上海"]))
# 添加/修改列
df.with_columns(
(pl.col("salary") * 1.1).alias("salary_after_raise")
)
# 分组聚合
df.group_by("city").agg([
pl.col("salary").mean().alias("avg_salary"),
pl.col("age").max().alias("max_age"),
pl.len().alias("count"), # 行数
])惰性计算(LazyFrame)
python
# 使用 lazy() 启动惰性查询
q = (
df.lazy()
.filter(pl.col("age") > 25)
.group_by("city")
.agg(pl.col("salary").mean())
.sort("salary", descending=True)
)
# 查看执行计划
print(q.explain())
# 执行查询
result = q.collect()
# 自动优化:谓词下推、投影下推等# 使用 lazy() 启动惰性查询
q = (
df.lazy()
.filter(pl.col("age") > 25)
.group_by("city")
.agg(pl.col("salary").mean())
.sort("salary", descending=True)
)
# 查看执行计划
print(q.explain())
# 执行查询
result = q.collect()
# 自动优化:谓词下推、投影下推等Polars vs Pandas 对比
| 特性 | Pandas | Polars |
|---|---|---|
| 底层语言 | Python / C | Rust |
| 索引 | 有行索引 | 无索引 |
| 表达式系统 | 链式调用 | Expr 表达式 |
| 惰性计算 | 不支持原生 | 原生支持 |
| 多线程 | 有限(单线程为主) | 全量多线程 |
| 内存效率 | 较高内存占用 | 高(零拷贝) |
| API 风格 | 命令式 | 表达式驱动 |
| 迁移学习成本 | - | 较低(概念类似) |
从 Pandas 迁移
python
import pandas as pd
import polars as pl
# pandas_df → polars_df
polars_df = pl.from_pandas(pandas_df)
# polars_df → pandas_df
pandas_df = polars_df.to_pandas()
# 常用操作对照
pl.col("col").mean() # df["col"].mean()
pl.col("col").alias("新名") # df["col"].rename("新名")
df.filter(cond) # df[cond]
df.with_columns(...) # df.assign(...)
df.group_by("col").agg(...) # df.groupby("col").agg(...)import pandas as pd
import polars as pl
# pandas_df → polars_df
polars_df = pl.from_pandas(pandas_df)
# polars_df → pandas_df
pandas_df = polars_df.to_pandas()
# 常用操作对照
pl.col("col").mean() # df["col"].mean()
pl.col("col").alias("新名") # df["col"].rename("新名")
df.filter(cond) # df[cond]
df.with_columns(...) # df.assign(...)
df.group_by("col").agg(...) # df.groupby("col").agg(...)适用场景
- 大数据集(百万到亿级行):Polars 优势明显
- ETL 管道:惰性计算 + 自动优化
- Parquet 文件处理:原生高性能支持
- 需要高性能的生产环境
数据处理的最佳实践
- 使用NumPy进行数值计算:NumPy的数组操作比Python列表快得多,适合大规模数值计算
- 使用Pandas处理结构化数据:Pandas提供了强大的数据结构和数据处理功能,适合处理结构化数据
- 优先使用向量化操作:避免使用Python循环,尽可能使用NumPy和Pandas的向量化操作
- 注意内存使用:对于大型数据集,使用适当的数据类型(如float32代替float64),并及时释放不再使用的变量
- 数据清洗和预处理:在进行数据分析前,确保数据质量,处理缺失值、重复值和异常值
- 使用适当的可视化方式:根据数据类型和分析目的选择合适的可视化方式
- 文档和注释:为代码添加文档和注释,便于理解和维护
- 测试代码:编写测试用例,确保代码的正确性
总结
NumPy和Pandas是Python中最重要的数据处理和分析库,它们提供了强大的数据结构和数据处理功能。NumPy是科学计算的基础,适合处理数值数据和数组操作;Pandas则适合处理结构化数据,提供了数据读取、清洗、预处理、聚合和可视化等功能。
通过学习和掌握这些库,我们可以更高效地处理和分析数据,为数据科学和机器学习项目打下坚实的基础。
Cao Note