Pandas 股票数据分析详解
1. 股票数据分析概述
Pandas 是进行股票数据分析的核心工具,它可以高效处理时间序列数据、计算技术指标、进行统计分析和可视化。典型流程包括:
- 数据获取:从 CSV、API 或数据库加载股票数据。
- 数据清洗:处理缺失值、异常值和格式转换。
- 特征工程:计算移动平均、回报率、技术指标(如 RSI、MACD)。
- 统计分析:相关性、波动率、风险指标。
- 可视化:K 线图、趋势图、热力图。
- 高级应用:回测策略、风险评估、多股比较。
本文使用模拟数据演示核心功能。实际应用中,可结合 yfinance
或 pandas_datareader
获取真实数据(需安装相关库)。
2. 数据获取与准备
2.1 模拟股票数据
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保可重复
np.random.seed(42)
# 生成模拟股票数据(AAPL 示例)
dates = pd.date_range('2023-01-01', periods=365, freq='D') # 一年数据
data = {
'Date': dates,
'Open': np.random.uniform(150, 160, len(dates)),
'High': np.random.uniform(160, 170, len(dates)),
'Low': np.random.uniform(140, 150, len(dates)),
'Close': np.random.uniform(150, 160, len(dates)),
'Volume': np.random.randint(1000000, 5000000, len(dates))
}
df = pd.DataFrame(data)
df.set_index('Date', inplace=True)
# 添加真实趋势模拟(假设向上趋势)
df['Close'] = df['Close'].cumsum() * 0.1 + 150 + np.random.randn(len(df)) * 5
df['Open'] = df['Close'] * np.random.uniform(0.98, 1.02, len(df))
df['High'] = df[['Open', 'Close']].max(axis=1) * np.random.uniform(1.01, 1.05, len(df))
df['Low'] = df[['Open', 'Close']].min(axis=1) * np.random.uniform(0.95, 0.99, len(df))
print("模拟股票数据预览:")
print(df.head())
2.2 真实数据获取示例
# 注意:需安装 yfinance(pip install yfinance)
# import yfinance as yf
# # 下载真实数据
# real_df = yf.download('AAPL', start='2023-01-01', end='2023-12-31')
# print("真实AAPL数据预览:")
# print(real_df.head())
3. 数据清洗
3.1 缺失值处理
# 检查缺失值
missing = df.isnull().sum()
print("缺失值统计:")
print(missing[missing > 0])
# 填充缺失值(例如,使用前向填充)
df = df.fillna(method='ffill')
df = df.fillna(method='bfill') # 后向填充剩余
# 删除异常值(例如,薪资负值或体积异常)
df = df[(df['Close'] > 0) & (df['Volume'] > 0)]
print("清洗后数据形状:", df.shape)
3.2 异常值检测
# IQR 方法检测异常值
def detect_outliers(series):
Q1 = series.quantile(0.25)
Q3 = series.quantile(0.75)
IQR = Q3 - Q1
return (series < Q1 - 1.5 * IQR) | (series > Q3 + 1.5 * IQR)
outliers = detect_outliers(df['Close'])
print("Close价格异常值数量:", outliers.sum())
# 替换异常值为中位数
median_close = df['Close'].median()
df.loc[outliers, 'Close'] = median_close
4. 特征工程与技术指标
4.1 计算回报率
# 日回报率
df['daily_return'] = df['Close'].pct_change().fillna(0)
# 累计回报率
df['cum_return'] = (1 + df['daily_return']).cumprod() - 1
print("回报率预览:")
print(df[['Close', 'daily_return', 'cum_return']].head())
4.2 移动平均线(MA)
# 简单移动平均(SMA)
df['MA5'] = df['Close'].rolling(window=5).mean()
df['MA20'] = df['Close'].rolling(window=20).mean()
df['MA50'] = df['Close'].rolling(window=50).mean()
# 指数移动平均(EMA)
df['EMA5'] = df['Close'].ewm(span=5, adjust=False).mean()
df['EMA20'] = df['Close'].ewm(span=20, adjust=False).mean()
print("移动平均预览:")
print(df[['Close', 'MA5', 'EMA5']].head(10))
4.3 RSI(相对强弱指数)
def calculate_rsi(series, period=14):
"""计算RSI"""
delta = series.diff()
gain = delta.where(delta > 0, 0).rolling(window=period).mean()
loss = -delta.where(delta < 0, 0).rolling(window=period).mean()
rs = gain / loss
return 100 - (100 / (1 + rs))
df['RSI'] = calculate_rsi(df['Close'])
print("RSI预览:")
print(df[['Close', 'RSI']].tail())
4.4 MACD(移动平均收敛散度)
def calculate_macd(series, short=12, long=26, signal=9):
"""计算MACD"""
ema_short = series.ewm(span=short, adjust=False).mean()
ema_long = series.ewm(span=long, adjust=False).mean()
macd = ema_short - ema_long
signal_line = macd.ewm(span=signal, adjust=False).mean()
histogram = macd - signal_line
return macd, signal_line, histogram
df['MACD'], df['Signal'], df['Histogram'] = calculate_macd(df['Close'])
print("MACD预览:")
print(df[['Close', 'MACD', 'Signal', 'Histogram']].tail())
5. 统计分析
5.1 描述性统计
print("股票数据统计摘要:")
print(df[['Close', 'Volume', 'daily_return']].describe())
# 分位数
quantiles = df['Close'].quantile([0.25, 0.5, 0.75])
print("\nClose价格分位数:")
print(quantiles)
5.2 波动率分析
# 日波动率(标准差)
df['volatility'] = df['daily_return'].rolling(window=30).std() * np.sqrt(252) # 年化波动率
print("波动率预览:")
print(df[['daily_return', 'volatility']].tail())
# 历史波动率
historical_vol = df['daily_return'].std() * np.sqrt(252)
print("\n年化历史波动率:", round(historical_vol, 4))
5.3 相关性分析
# 简单相关性
corr_matrix = df[['Close', 'Volume', 'RSI', 'MACD']].corr()
print("相关系数矩阵:")
print(corr_matrix)
# 热力图可视化
import seaborn as sns
plt.figure(figsize=(8, 6))
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm')
plt.title('股票指标相关性热力图')
plt.show()
5.4 风险指标
# 最大回撤
def max_drawdown(returns):
"""计算最大回撤"""
cum_returns = (1 + returns).cumprod()
peak = cum_returns.cummax()
drawdown = (cum_returns - peak) / peak
return drawdown.min()
mdd = max_drawdown(df['daily_return'])
print("最大回撤:", round(mdd, 4))
# 夏普比率(年化)
risk_free_rate = 0.03 # 假设无风险利率
sharpe = (df['daily_return'].mean() * 252 - risk_free_rate) / (df['daily_return'].std() * np.sqrt(252))
print("夏普比率:", round(sharpe, 4))
6. 数据可视化
6.1 K线图
# 注意:需安装 mplfinance(pip install mplfinance)
# from mplfinance.original_flavor import candlestick_ohlc
# import matplotlib.dates as mdates
# df_ohlc = df[['Open', 'High', 'Low', 'Close']].reset_index()
# df_ohlc['Date'] = mdates.date2num(df_ohlc['Date'])
# fig, ax = plt.subplots(figsize=(12, 6))
# candlestick_ohlc(ax, df_ohlc.values, width=0.6, colorup='g', colordown='r')
# ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
# plt.title('股票K线图')
# plt.xticks(rotation=45)
# plt.show()
6.2 趋势图与指标
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10), sharex=True)
# 价格趋势
ax1.plot(df.index, df['Close'], label='Close')
ax1.plot(df.index, df['MA20'], label='MA20')
ax1.plot(df.index, df['MA50'], label='MA50')
ax1.set_title('股票价格趋势')
ax1.legend()
# RSI与MACD
ax2.plot(df.index, df['RSI'], label='RSI')
ax2.axhline(70, color='r', linestyle='--', label='Overbought')
ax2.axhline(30, color='g', linestyle='--', label='Oversold')
ax2.set_title('RSI指标')
ax2.legend()
plt.tight_layout()
plt.show()
6.3 回报率分布
plt.figure(figsize=(10, 6))
df['daily_return'].hist(bins=50)
plt.title('日回报率分布')
plt.xlabel('回报率')
plt.ylabel('频数')
plt.show()
7. 高级分析
7.1 回测简单策略
# 移动平均交叉策略
df['signal'] = np.where(df['MA5'] > df['MA20'], 1, 0)
df['strategy_return'] = df['signal'].shift(1) * df['daily_return']
# 累计回报
df['strategy_cum'] = (1 + df['strategy_return']).cumprod() - 1
plt.figure(figsize=(12, 6))
df['cum_return'].plot(label='买入持有')
df['strategy_cum'].plot(label='MA交叉策略')
plt.title('策略回测')
plt.ylabel('累计回报')
plt.legend()
plt.show()
7.2 多股相关性分析
# 模拟多股数据
stocks = pd.DataFrame({
'AAPL': df['Close'],
'GOOG': df['Close'] * 1.2 + np.random.randn(len(df)) * 10,
'MSFT': df['Close'] * 0.8 + np.random.randn(len(df)) * 5
})
# 相关性
multi_corr = stocks.corr()
print("多股相关性:")
print(multi_corr)
plt.figure(figsize=(8, 6))
sns.heatmap(multi_corr, annot=True, cmap='coolwarm')
plt.title('股票相关性热力图')
plt.show()
8. 性能考虑
- 大数据处理:对于海量数据,使用
Dask
或Modin
并行化 Pandas 操作。 - 实时分析:结合
Streamlit
或Dash
构建交互式仪表板。 - 机器学习集成:使用 Scikit-learn 构建预测模型,例如基于 RSI 和 MACD 预测股价趋势。
Pandas 股票数据分析结合时间序列处理、统计计算和可视化,是量化投资的核心工具。通过实际项目练习,可以深入掌握其应用。建议结合真实 API 数据进行扩展。