如何无循环逐行遍历同构Pandas DataFrame并传参给函数
实现类似R中mapply的Pandas逐行向量处理
问题描述
希望不使用显式循环,逐行遍历两个形状完全相同的Pandas DataFrame,将每个DataFrame的对应行作为向量传入函数,实现类似R语言中mapply的功能。现有代码尝试用列表推导+map实现,但未得到预期结果(期望输出3个值,对应3行),且写法繁琐,想找更优雅的内置实现方式。
原代码:
import numpy as np import pandas as pd from scipy import stats df1 = pd.DataFrame(np.random.randn(3,3)) df2 = pd.DataFrame(np.random.randn(3,3)) sd_array = np.array([0.02, 0.015, 0.2]) def helper_func(x, y): return stats.norm.pdf(x, loc=y, scale=sd_array).prod() res_lst = [] row_cnt = df1.shape[0] res = [list(map(helper_func, df1.iloc[i,:], df2.iloc[i,:])) for i in range(row_cnt)] res_lst.append(res)
问题分析
原代码的问题在于:map(helper_func, df1.iloc[i,:], df2.iloc[i,:])是把每行的单个元素一一传入helper_func,而非将整行作为向量传入,所以每行会生成3个值,最终得到3×3的结果,和预期的3个值不符。
优雅解决方案
方法1:简洁的逐行迭代方式
直接将DataFrame转为数组后用zip配对行向量,配合列表推导实现,代码直观且无冗余:
import numpy as np import pandas as pd from scipy import stats df1 = pd.DataFrame(np.random.randn(3,3)) df2 = pd.DataFrame(np.random.randn(3,3)) sd_array = np.array([0.02, 0.015, 0.2]) def helper_func(x, y): return stats.norm.pdf(x, loc=y, scale=sd_array).prod() # 将DataFrame转为二维数组,zip后每次迭代取对应行的向量 result = [helper_func(x, y) for x, y in zip(df1.to_numpy(), df2.to_numpy())] print(result)
方法2:Pandas内置apply方法
利用apply指定axis=1逐行处理,适合习惯Pandas原生API的场景:
import numpy as np import pandas as pd from scipy import stats df1 = pd.DataFrame(np.random.randn(3,3)) df2 = pd.DataFrame(np.random.randn(3,3)) sd_array = np.array([0.02, 0.015, 0.2]) # 合并两个DataFrame的列,让apply能同时获取对应行的两组数据 combined_df = pd.concat([df1, df2], axis=1) def helper_func(row): x = row[:3].values # 取合并后行的前3列,对应df1的行 y = row[3:].values # 取合并后行的后3列,对应df2的行 return stats.norm.pdf(x, loc=y, scale=sd_array).prod() # 逐行应用函数,输出结果转为列表 result = combined_df.apply(helper_func, axis=1).tolist() print(result)
方法3:向量化操作(性能最优)
完全利用Numpy的向量化特性,避免逐行迭代,大数据量下速度最快:
import numpy as np import pandas as pd from scipy import stats df1 = pd.DataFrame(np.random.randn(3,3)) df2 = pd.DataFrame(np.random.randn(3,3)) sd_array = np.array([0.02, 0.015, 0.2]) # 直接对整个DataFrame的数组进行向量化计算 pdf_matrix = stats.norm.pdf(df1.to_numpy(), loc=df2.to_numpy(), scale=sd_array) # 按行求乘积,得到每行的结果 result = pdf_matrix.prod(axis=1).tolist() print(result)
总结
- 追求代码简洁:优先选择
zip+列表推导的方式,逻辑清晰无冗余; - 习惯Pandas原生API:使用
apply方法,符合Pandas的使用习惯; - 追求极致性能:用向量化操作,这是Pandas/Numpy的原生最优方案。
内容的提问来源于stack exchange,提问作者matsuo_basho
相关产品推荐
相关产品推荐

