如何让过滤后的Pandas DataFrame支持按引用更新
问题描述
我通过sell_shares函数过滤DataFrame,代码如下:
def sell_shares(df_company, number_shares, date_end): df_filtered = df_company.copy()[(df_company['Date'] <= date_end)] df_filtered['Date'] = pd.to_datetime(df_filtered['Date'], dayfirst=True) remaining_shares = number_shares # default for i, row in df_filtered.iterrows(): row = df_filtered.iloc[i] remaining_shares, df_filtered = remove_shares(df_filtered, i, remaining_shares)
随后调用remove_shares函数并传入df_filtered:
def remove_shares(df, i, number_shares): #print("Considering row: ", row) print("Before sell, Number of shares: {:}".format(df.iloc[i]["Quantity"])) remaining_shares = 0 if abs(number_shares) < abs(df.iloc[i]["Quantity"]): # have less than in batch - so decrement #row.columns.set_loc("Quantity") += - abs(number_shares) #row["Quantity"] += - abs(number_shares) df.iloc[i, df.columns.get_loc("Quantity")] += - abs(number_shares)
我的原始调用函数如下:
def compute_gain_before_tax_year(df, company_name, date_start, date_end): df_company = df.copy(deep=True) df_company = df_company[df_company["Market"]==company_name] df_company = df_company[( df_company["Date"] < pd.to_datetime(date_start, dayfirst=True))]
问题:当我最终执行df.iloc[i, df.columns.get_loc("Quantity")] = 0更新DataFrame时,如何确保所有操作都按引用进行?我在remove_shares函数中能看到本地的修改,但这些修改无法向上传递到上层。
问题分析
- DataFrame引用断裂:Pandas DataFrame是引用传递,但如果在函数内执行切片、过滤或
copy()操作,会生成新的独立对象,导致上层原对象与修改后的对象断开关联。 - 返回逻辑缺失:
remove_shares未返回修改后的DataFrame,sell_shares也未将最终修改结果传递给上层调用函数。 - 冗余操作:
sell_shares中df_filtered = df_company.copy()[(df_company['Date'] <= date_end)]属于冗余操作,先copy再切片会额外生成副本,加剧引用断裂问题。
修复方案
1. 修正sell_shares的对象生成与返回逻辑
避免冗余copy操作,确保返回修改后的DataFrame:
def sell_shares(df_company, number_shares, date_end): # 先过滤再copy,减少中间对象生成 df_filtered = df_company[(df_company['Date'] <= date_end)].copy() df_filtered['Date'] = pd.to_datetime(df_filtered['Date'], dayfirst=True) remaining_shares = number_shares for i, _ in df_filtered.iterrows(): # 直接传入索引,无需重复获取row remaining_shares, df_filtered = remove_shares(df_filtered, i, remaining_shares) # 将修改后的DataFrame返回给上层 return df_filtered
2. 完善remove_shares的业务逻辑与返回
补全卖出逻辑,确保返回修改后的DataFrame和剩余待卖股份数:
def remove_shares(df, i, number_shares): current_quantity = abs(df.iloc[i]["Quantity"]) print("Before sell, Number of shares: {:}".format(current_quantity)) sell_amount = abs(number_shares) if sell_amount < current_quantity: # 卖出数量小于当前持仓,扣除对应份额 df.iloc[i, df.columns.get_loc("Quantity")] -= sell_amount remaining_shares = 0 else: # 卖出数量大于等于当前持仓,清空该行持仓 df.iloc[i, df.columns.get_loc("Quantity")] = 0 remaining_shares = sell_amount - current_quantity # 返回剩余待卖数和修改后的DataFrame return remaining_shares, df
3. 上层函数接收修改结果
在compute_gain_before_tax_year中接收sell_shares返回的修改后DataFrame:
def compute_gain_before_tax_year(df, company_name, number_shares, date_start, date_end): df_company = df.copy(deep=True) df_company = df_company[df_company["Market"]==company_name] df_company = df_company[df_company["Date"] < pd.to_datetime(date_start, dayfirst=True)] # 接收修改后的DataFrame df_company_updated = sell_shares(df_company, number_shares, date_end) # 后续业务基于修改后的DataFrame处理 return df_company_updated
关键提示
如果想直接修改传入的原DataFrame而非返回新对象,需避免任何会生成副本的操作(如切片后赋值给新变量),但Pandas的视图/副本规则较复杂,明确返回修改后的DataFrame是更稳妥、易维护的方式。
内容的提问来源于stack exchange,提问作者disruptive
相关产品推荐
相关产品推荐

