为Pandas DataFrame应用多输入多输出函数时触发形状异常
问题分析与解决方案
你遇到的Shape of passed values is (1816, 2), indices imply (1816, 6)错误,核心原因是apply(axis=1)的返回结构和你预期的不符:你的函数返回两个值,但在当前pandas环境下,apply将其解析成了两列的DataFrame,而不是每个元素为二元组的Series,这就导致zip(*...)解包后的结构无法匹配原DataFrame的列数要求。
下面给出两种针对性的解决方案,同时优化你的代码可读性和准确性:
方案一:直接返回Series,批量赋值新列
修改函数返回为pd.Series,让apply直接生成包含结果的DataFrame,然后一次性赋值给新列:
import numpy as np import pandas as pd def calculate_solar_params(row): gsc = 1367 phi = np.deg2rad(row['Latitude']) date = row['Date'] # 直接从datetime对象获取年月日,避免冗余的DatetimeIndex创建 year = date.year month = date.month day = date.day # 更准确的闰年判断逻辑(处理整百年情况) is_leap = year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) B = (day - 1) * (360 / 366) if is_leap else (day - 1) * (360 / 365) B = np.deg2rad(B) delta = (0.006918 - 0.399912*np.cos(B) + 0.070257*np.sin(B) - 0.006758*np.cos(2*B) + 0.000907*np.sin(2*B) - 0.002697*np.cos(3*B) + 0.00148*np.sin(3*B)) ws = np.arccos(-np.tan(phi) * np.tan(delta)) daylength = (2/15) * np.rad2deg(ws) # 修正拼写错误 dayangle = np.deg2rad(360 * day / 366) if is_leap else np.deg2rad(360 * day / 365) h0_value = (24*3600*gsc/np.pi) * (1 + 0.033*np.cos(dayangle)) * (np.cos(phi)*np.cos(delta)*np.sin(ws) + ws*np.sin(phi)*np.sin(delta)) # 返回Series,指定列名更清晰 return pd.Series([h0_value, daylength], index=['h0', 'daylength']) # 直接将结果赋值给新列 ak[['h0', 'N']] = ak.apply(calculate_solar_params, axis=1)
方案二:强制返回元组,用zip解包
如果希望继续使用zip(*...)的方式,需要确保apply返回的是每个元素为二元组的Series,同时优化代码细节:
import numpy as np import pandas as pd def calculate_solar_params(row): gsc = 1367 phi = np.deg2rad(row['Latitude']) date = row['Date'] year = date.year month = date.month day = date.day is_leap = year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) B = (day - 1) * (360 / 366) if is_leap else (day - 1) * (360 / 365) B = np.deg2rad(B) delta = (0.006918 - 0.399912*np.cos(B) + 0.070257*np.sin(B) - 0.006758*np.cos(2*B) + 0.000907*np.sin(2*B) - 0.002697*np.cos(3*B) + 0.00148*np.sin(3*B)) ws = np.arccos(-np.tan(phi) * np.tan(delta)) daylength = (2/15) * np.rad2deg(ws) dayangle = np.deg2rad(360 * day / 366) if is_leap else np.deg2rad(360 * day / 365) h0_value = (24*3600*gsc/np.pi) * (1 + 0.033*np.cos(dayangle)) * (np.cos(phi)*np.cos(delta)*np.sin(ws) + ws*np.sin(phi)*np.sin(delta)) # 显式返回元组,确保apply生成Series of tuples return (h0_value, daylength) # 解包并赋值新列 ak['h0'], ak['N'] = zip(*ak.apply(calculate_solar_params, axis=1))
额外优化说明
- 修正了变量名
daylenght的拼写错误为daylength,避免后续使用混淆; - 替换了冗余的
pd.DatetimeIndex创建逻辑,直接从datetime对象获取年月日,提升代码效率; - 使用更严谨的闰年判断逻辑,支持整百年的闰年校验(比如2000年是闰年,1900年不是);
- 将函数内的
h0变量名改为h0_value,避免和函数名冲突,提高代码可读性。
内容的提问来源于stack exchange,提问作者Erol Can Akbaba
相关产品推荐
相关产品推荐

