如何将Pandas函数应用于DataFrame并合并结果为新DataFrame
问题:批量处理股票涨跌幅函数后无法合并DataFrame
我编写的get_returns_change_period函数可单独计算指定股票不同周期的涨跌幅(例如传入'XOM','EXXON MOBIL','High','Open'可正常运行),但通过lambda结合apply批量处理存储行业股票信息的df_Industry DataFrame时,无法将函数返回的多个股票DataFrame合并为一个统一的结果DataFrame。
原代码
涨跌幅计算函数
import pandas as pd import yfinance as yF import datetime from functools import reduce def get_returns_change_period(tic,com,OHLC_COL1,OHLC_COL2): df_Stock = yF.download(tickers = tic, period = "38y", interval = "1mo", prepost = False, repair = False) df_Stock['MONTH'] = pd.to_datetime(df_Stock.index) df_Stock = df_Stock.sort_values(by='MONTH') # 原计算逻辑存在重复错误,后续会修正 df_Stock[com + ' % Change '+'3M'] = (((df_Stock[OHLC_COL1].shift(2) - df_Stock[OHLC_COL2]))/df_Stock[OHLC_COL2]) *100 df_Stock[com + ' % Change '+'3M'] = (df_Stock[com + ' % Change '+'3M'] * 100 )/df_Stock[OHLC_COL2] df_Stock[com + ' % Change '+'2M'] = (((df_Stock[OHLC_COL1].shift(1) - df_Stock[OHLC_COL2]))/df_Stock[OHLC_COL2]) *100 df_Stock[com + ' % Change '+'2M'] = (df_Stock[com + ' % Change '+'2M'] * 100 )/df_Stock[OHLC_COL2] df_Stock[com + ' % Change '+'M'] = (((df_Stock[OHLC_COL1].shift(0) - df_Stock[OHLC_COL2]))/df_Stock[OHLC_COL2]) *100 df_Stock[com + ' % Change '+'M'] = (df_Stock[com + ' % Change '+'M'] * 100 )/df_Stock[OHLC_COL2] return df_Stock.filter(regex='MONTH|% Change')
单独调用示例
get_returns_change_period('XOM','EXXON MOBIL','High','Open')
批量处理代码
df_Industry = pd.DataFrame({'ID':['1', '2'], 'Ticker': ['AIN', 'TILE'], 'Company':['Albany International', 'Interface']}) df1 = df_Industry.apply(lambda x: get_returns_change_period(x.Ticker, x.Company, 'High','Open'), axis=1) df1
解决方案
步骤1:修正函数中的涨跌幅计算逻辑
原函数中重复执行了*100 / df_Stock[OHLC_COL2],导致计算结果严重偏离实际涨跌幅。正确的涨跌幅公式应为((后期值 - 初始值)/初始值)*100,修正后的函数如下:
def get_returns_change_period(tic, com, OHLC_COL1, OHLC_COL2): df_Stock = yF.download(tickers=tic, period="38y", interval="1mo", prepost=False, repair=False) df_Stock['MONTH'] = pd.to_datetime(df_Stock.index) df_Stock = df_Stock.sort_values(by='MONTH') # 修正后的涨跌幅计算逻辑 # 注:shift(-2)表示取2个月后的OHLC_COL1值,若要对比过去2个月的数值,可改为shift(2) df_Stock[f'{com} % Change 3M'] = ((df_Stock[OHLC_COL1].shift(-2) - df_Stock[OHLC_COL2]) / df_Stock[OHLC_COL2]) * 100 df_Stock[f'{com} % Change 2M'] = ((df_Stock[OHLC_COL1].shift(-1) - df_Stock[OHLC_COL2]) / df_Stock[OHLC_COL2]) * 100 df_Stock[f'{com} % Change M'] = ((df_Stock[OHLC_COL1] - df_Stock[OHLC_COL2]) / df_Stock[OHLC_COL2]) * 100 # 将MONTH设为索引,方便后续按月份对齐合并 df_Stock = df_Stock.set_index('MONTH') return df_Stock.filter(regex='% Change')
步骤2:批量处理并合并DataFrame
使用列表推导式遍历df_Industry的每一行,获取单个股票的结果DataFrame,再通过pd.concat横向合并(自动按月份索引对齐,缺失月份填充为NaN):
df_Industry = pd.DataFrame({'ID':['1', '2'], 'Ticker': ['AIN', 'TILE'], 'Company':['Albany International', 'Interface']}) # 遍历每行获取单个股票的结果DataFrame stock_dfs = [get_returns_change_period(row.Ticker, row.Company, 'High','Open') for _, row in df_Industry.iterrows()] # 横向合并所有DataFrame,按月份索引自动对齐 result_df = pd.concat(stock_dfs, axis=1) # 可选:将MONTH从索引恢复为普通列 result_df = result_df.reset_index()
替代方案:多股票场景下用reduce合并
如果处理的股票数量较多,可结合reduce和pd.merge按MONTH列进行outer合并,确保保留所有股票的所有月份数据:
from functools import reduce # 调整函数,保留MONTH为普通列(不设为索引) def get_returns_change_period(tic, com, OHLC_COL1, OHLC_COL2): df_Stock = yF.download(tickers=tic, period="38y", interval="1mo", prepost=False, repair=False) df_Stock['MONTH'] = pd.to_datetime(df_Stock.index) df_Stock = df_Stock.sort_values(by='MONTH') df_Stock[f'{com} % Change 3M'] = ((df_Stock[OHLC_COL1].shift(-2) - df_Stock[OHLC_COL2]) / df_Stock[OHLC_COL2]) * 100 df_Stock[f'{com} % Change 2M'] = ((df_Stock[OHLC_COL1].shift(-1) - df_Stock[OHLC_COL2]) / df_Stock[OHLC_COL2]) * 100 df_Stock[f'{com} % Change M'] = ((df_Stock[OHLC_COL1] - df_Stock[OHLC_COL2]) / df_Stock[OHLC_COL2]) * 100 return df_Stock.filter(regex='MONTH|% Change') stock_dfs = [get_returns_change_period(row.Ticker, row.Company, 'High','Open') for _, row in df_Industry.iterrows()] # 按MONTH列outer合并所有DataFrame result_df = reduce(lambda left, right: pd.merge(left, right, on='MONTH', how='outer'), stock_dfs)
内容的提问来源于stack exchange,提问作者prashanth manohar
相关产品推荐
相关产品推荐

