如何简洁计算Pandas Series每行向量与下一行的百分比变化?
计算Pandas Series中每行向量与下一行的百分比变化
需求说明
计算Pandas Series中每行的向量与下一行对应位置元素的百分比变化,公式为(当前行元素 - 下一行元素) / 下一行元素,最后一行因无后续行,结果返回None。
示例输入
import pandas as pd a = pd.Series([[1,2,3],[4,5,6],[7,8,9]]) a
输出:
0 [1, 2, 3] 1 [4, 5, 6] 2 [7, 8, 9] dtype: object
期望输出
0 [-0.75, -0.6, -0.5] 1 [-0.42857142857142855, -0.375, -0.333333333333... 2 None dtype: object
现有解法问题
当前使用嵌套列表推导式实现,但写法过于复杂,可读性差:
import pandas as pd a = pd.Series([[1,2,3],[4,5,6],[7,8,9]]) pd.Series([ [ [ (xx-yy)/yy for xx,yy in zip(x,y)] if y is not None else None] for x,y in zip(a,a.shift(-1))])
简洁实现方案
方案1:结合apply与shift
利用shift(-1)获取下一行数据,通过apply逐行计算,逻辑更直观:
import pandas as pd a = pd.Series([[1,2,3],[4,5,6],[7,8,9]]) def calc_pct_change(current, next_row): if next_row is None: return None return [(curr - nxt)/nxt for curr, nxt in zip(current, next_row)] result = pd.Series([calc_pct_change(x, y) for x, y in zip(a, a.shift(-1))]) print(result)
也可简化为lambda表达式,省去函数定义:
result = a.shift(-1).combine(a, lambda nxt, curr: [(c - n)/n for c, n in zip(curr, nxt)] if nxt is not None else None)
方案2:转换为DataFrame处理(更符合Pandas原生逻辑)
Series存储列表并非最优用法,转为DataFrame后可利用向量化运算,效率更高:
import pandas as pd a = pd.Series([[1,2,3],[4,5,6],[7,8,9]]) # 将Series转换为DataFrame df = pd.DataFrame(a.tolist()) # 向量化计算百分比变化 pct_change = (df - df.shift(-1)) / df.shift(-1) # 将每行结果转回列表格式,最后一行填充None result = pct_change.apply(list, axis=1).fillna(pd.Series([None], index=[len(a)-1])) print(result)
内容的提问来源于stack exchange,提问作者DS_London
相关产品推荐
相关产品推荐

