循环中无法为Pandas DataFrame新列正确赋值的问题排查
问题
无法在循环中为Pandas DataFrame的新列正确赋值。程序整体运行正常,仅一行代码异常——需要将原始DataFrame的行追加到Feasible_Distribution_Plan后,给这个新DataFrame添加Distance to Site Location列,存储每次选中的Warehouse对应的仓库到站点的距离,但当前代码实现不了。
相关代码
原始DataFrame定义
import pandas as pd df = pd.DataFrame({ 'Name': {0: 'a', 1: 'c', 2: 'j', 3: 'd', 4: 'e'}, 'Type': {0: 1, 1: 1, 2: 1, 3: 2, 4: 2}, 'Number of Beams': {0: 60, 1: 60, 2: 60, 3: 60, 4: 60}, 'Number of Columns': {0: 25, 1: 25, 2: 25, 3: 25, 4: 25}, 'Total Weight': {0: 120, 1: 125, 2: 130, 3: 145, 4: 145}, 'Warehouse1 Distance to Site Location': {0: 968, 1: 447, 2: 580, 3: 245, 4: 100}, 'Warehouse2 Distance to Site Location': {0: 220, 1: 513, 2: 123, 3: 35, 4: 940}, 'Warehouse3 Distance to Site Location': {0: 215, 1: 617, 2: 319, 3: 175, 4: 228}, 'Minimum Distance to Site Location': {0: 215, 1: 447, 2: 123, 3: 35, 4: 100}, 'Date of Registeration': {0: 0, 1: 0, 2: 0, 3: 0, 4: 0}, 'Earliest Time to Deliver': {0: 8, 1: 9, 2: 7, 3: 8, 4: 8}, 'Latest Time to Deliver': {0: 10, 1: 10, 2: 11, 3: 12, 4: 9}, 'Frame Cost': {0: 3720, 1: 3875, 2: 4030, 3: 4495, 4: 4495}, 'Transportation Cost': {0: 516, 1: 1117.5, 2: 319.8, 3: 101.5, 4: 290}, 'Date of Delivery': {0: 8, 1: 9, 2: 7, 3: 8, 4: 8} })
初始化参数
import copy current_day = 0 Charge = [250, 130, 140, 200] Capacities = { 1: {"Warehouse1":250, "Warehouse2":250, "Warehouse3":250}, 2: {"Warehouse1":130, "Warehouse2":130, "Warehouse3":130}, 3: {"Warehouse1":140, "Warehouse2":140, "Warehouse3":140}, 4: {"Warehouse1":200, "Warehouse2":200, "Warehouse3":200} } Daily_Capacities = [] Indicator = 0 Feasible_Distribution_Plan = pd.DataFrame() # 补充初始化,避免运行报错
仓库选择函数
def Select_Warhouse(df, li): min_col = None min_val = float('inf') results = [] for dict_item in li: for key in dict_item.keys(): matching_col = [col for col in df.columns if key in col] if matching_col: col_name = matching_col[0] col_val = df.iloc[0][col_name] results.append((col_name, col_val)) if col_val < min_val: min_col = col_name min_val = col_val output = [el for el in li if list(el.keys())[0] in min_col.split()[0]] return str(*output[0].keys())
主循环逻辑
while len(df) > 0: if current_day % 15 == 0 and current_day != 0 and Indicator == 0: for i, j in zip(Capacities, Charge): for key in Capacities[i]: Capacities[i][key] = Capacities[i][key] + j Indicator = 0 select = df[df['Date of Delivery'] == current_day] if len(select) == 0: Daily_Capacities.append(copy.deepcopy(Capacities)) current_day += 1 continue if len(select) > 1: Indicator = 1 select = select[select['Total Weight'] == select['Total Weight'].max()] if len(select) > 1: select = select[select['Latest Time to Deliver'] == select['Latest Time to Deliver'].min()] if len(select) > 1: select = select.sample() Available_Warehouses = [] for key, value in Capacities[select['Type'].iloc[0]].items(): if select['Total Weight'].iloc[0] <= value: Available_Warehouses.append({key:value}) if len(Available_Warehouses) == 0: df.loc[select.index, 'Date of Delivery'] += 1 if Indicator == 1: continue Daily_Capacities.append(copy.deepcopy(Capacities)) current_day += 1 continue elif len(Available_Warehouses) == 1: Warehouse = str(*Available_Warehouses[0].keys()) elif len(Available_Warehouses) > 1: Warehouse = Select_Warhouse(select, Available_Warehouses) Feasible_Distribution_Plan = Feasible_Distribution_Plan.append(select.iloc[0], ignore_index= True) # 异常代码行 Feasible_Distribution_Plan['Distance to Site Location'] = Feasible_Distribution_Plan.iloc[-1]['{} Distance to Site Location'.format(Warehouse)] df.drop(select.index, inplace= True) Capacities[select['Type'].iloc[0]][Warehouse] -= select.iloc[0]['Total Weight'] if Indicator == 1: continue Daily_Capacities.append(copy.deepcopy(Capacities)) current_day += 1 Feasible_Distribution_Plan['Date of Delivery'] = Feasible_Distribution_Plan['Date of Delivery'].astype('int32') Feasible_Distribution_Plan
异常代码行
Feasible_Distribution_Plan['Distance to Site Location'] = Feasible_Distribution_Plan.iloc[-1]['{} Distance to Site Location'.format(Warehouse)]
解决方案
你的问题出在赋值逻辑:每次追加行后,你直接把整个Distance to Site Location列设置成最后一行对应仓库的距离,导致所有行的该值都被覆盖成最新的那个。正确做法是只给刚追加的那一行赋值,而非整列。
方式1:追加前给行添加列(推荐)
先复制选中的行,添加新列后再追加到目标DataFrame:
# 替换原有的append和赋值两行 selected_row = select.iloc[0].copy() selected_row['Distance to Site Location'] = selected_row[f"{Warehouse} Distance to Site Location"] Feasible_Distribution_Plan = Feasible_Distribution_Plan.append(selected_row, ignore_index=True)
方式2:定位最后一行索引赋值
如果要保留先追加再赋值的逻辑,通过索引定位到刚添加的最后一行,仅修改该行的值:
# 追加行后执行 last_idx = Feasible_Distribution_Plan.index[-1] Feasible_Distribution_Plan.loc[last_idx, 'Distance to Site Location'] = Feasible_Distribution_Plan.iloc[-1][f"{Warehouse} Distance to Site Location"]
额外优化建议
- 避免循环中频繁调用
append:Pandas的DataFrame是不可变结构,每次append都会创建新对象,循环次数多了效率极低。建议先把所有要添加的行存入列表,最后一次性转成DataFrame:
# 初始化列表存行 plan_rows = [] # 循环中替换append逻辑 selected_row = select.iloc[0].copy() selected_row['Distance to Site Location'] = selected_row[f"{Warehouse} Distance to Site Location"] plan_rows.append(selected_row) # 循环结束后生成DataFrame Feasible_Distribution_Plan = pd.DataFrame(plan_rows)
- 原代码缺少
Feasible_Distribution_Plan的初始化,运行会报错,必须先添加Feasible_Distribution_Plan = pd.DataFrame()。
内容的提问来源于stack exchange,提问作者Ahmad__fazli
相关产品推荐
相关产品推荐

