如何对pandas DataFrame列内元素做环比除法并取自然对数?
问题描述
我被这段代码难住了。我有如下简单的DataFrame:
Business Date dic-22 gen-23 feb-23 03/10/2022 112,0 121,1 131,2 04/10/2022 87,0 103,0 122,5 05/10/2022 114,3 102,8 99,6 06/10/2022 101,7 116,6 104,3 07/10/2022 116,6 103,7 110,8 10/10/2022 108,8 107,3 112,0
我需要对每一列中的每个值与其前一个值做除法运算,例如dic-22列依次计算87/112、114/87……,最终得到如下结果:
Business Date dic-22 gen-23 feb-23 03/10/2022 0 0 0 04/10/2022 0,8 0,9 0,9 05/10/2022 1,3 1,0 0,8 06/10/2022 0,9 1,1 1,0 07/10/2022 1,1 0,9 1,1 10/10/2022 0,9 1,0 1,0
之后我还需要对这些结果取自然对数。我尝试实现但卡在了第一步(列内除法计算),以下代码无法正常运行:
for i, column in df.items(): for j, row in df.iterrows(): # if j > 0: # Skip first row df.iloc[:, 1:] = df.iloc[:, 1:] / df.iloc[:, 1:].shift()
解决方法
你的代码问题在于:
- 嵌套循环完全多余,pandas的矢量化操作可以直接处理列运算
- 原数据中的数值用逗号作为小数点分隔,属于字符串类型,无法直接进行除法计算
- 直接赋值会覆盖原DataFrame的原始数据
按以下步骤处理即可:
步骤1:转换数值格式
先把数值列的逗号替换为点,再转换成浮点数类型:
import pandas as pd import numpy as np # 假设你的DataFrame已加载,先定义数值列 numeric_cols = ['dic-22', 'gen-23', 'feb-23'] # 替换逗号为点并转成float df[numeric_cols] = df[numeric_cols].apply(lambda x: x.str.replace(',', '.').astype(float))
步骤2:计算列内环比比值
用shift()方法获取前一行数据,直接做除法运算,无需循环:
# 计算当前值与前一行值的比值 ratio_df = df[numeric_cols].div(df[numeric_cols].shift(1)) # 第一行没有前一行数据,替换为0 ratio_df.iloc[0] = 0
步骤3:生成示例格式的结果
合并日期列,并将小数点转回逗号以匹配示例格式:
# 合并日期列和比值列 result_df = pd.concat([df['Business Date'], ratio_df], axis=1) # 保留1位小数,再把点替换为逗号 result_df[numeric_cols] = result_df[numeric_cols].round(1).astype(str).str.replace('.', ',')
步骤4:对结果取自然对数
注意第一行的0无法取对数,需单独处理:
# 先把字符串转回数值类型 log_df = result_df[numeric_cols].replace(',', '.', regex=True).astype(float) # 对非0值取自然对数,0保持不变 log_df = log_df.apply(lambda x: np.where(x == 0, 0, np.log(x))) # 合并日期列得到最终对数结果 final_log_df = pd.concat([df['Business Date'], log_df], axis=1)
完整可运行代码
import pandas as pd import numpy as np # 构造你的DataFrame(模拟读取后的数据) data = { 'Business Date': ['03/10/2022', '04/10/2022', '05/10/2022', '06/10/2022', '07/10/2022', '10/10/2022'], 'dic-22': ['112,0', '87,0', '114,3', '101,7', '116,6', '108,8'], 'gen-23': ['121,1', '103,0', '102,8', '116,6', '103,7', '107,3'], 'feb-23': ['131,2', '122,5', '99,6', '104,3', '110,8', '112,0'] } df = pd.DataFrame(data) # 步骤1:转换数值格式 numeric_cols = ['dic-22', 'gen-23', 'feb-23'] df[numeric_cols] = df[numeric_cols].apply(lambda x: x.str.replace(',', '.').astype(float)) # 步骤2:计算环比比值 ratio_df = df[numeric_cols].div(df[numeric_cols].shift(1)) ratio_df.iloc[0] = 0 # 步骤3:生成示例格式结果 result_df = pd.concat([df['Business Date'], ratio_df], axis=1) result_df[numeric_cols] = result_df[numeric_cols].round(1).astype(str).str.replace('.', ',') print("比值结果:") print(result_df) # 步骤4:取自然对数 log_df = result_df[numeric_cols].replace(',', '.', regex=True).astype(float) log_df = log_df.apply(lambda x: np.where(x == 0, 0, np.log(x))) final_log_df = pd.concat([df['Business Date'], log_df], axis=1) print("\n对数结果:") print(final_log_df)
内容的提问来源于stack exchange,提问作者Medea00
相关产品推荐
相关产品推荐

