【问题标题】:Is there a better way to write a recursive `df.loc(t-1)` assignment than to use `.unique()`?有没有比使用 .unique() 更好的方法来编写递归的 df.loc(t-1) 赋值?
【发布时间】:2021-12-27 19:15:53
【问题描述】:

递归函数很难向量化,因为每个输入在时间 t 取决于时间 t-1 的先前输入。

[下面的问题更新为稍微复杂一点的例子 x_t = a x_{t-1} + b.]

.loc 返回不同数据类型的问题

import pandas
df1 = pandas.DataFrame({'year':range(2020,2024),'a':range(3,7)})
# Set the initial value
t0 = min(df1.year)
df1.loc[df1.year==t0, "x"] = 0

当等式的右边是 pandas.core.series.Series 时,此分配不起作用

for t in range (min(df1.year)+1, max(df1.year)+1):
    df1.loc[df1.year==t, "x"] = df1.loc[df1.year==t-1,"x"] + df1.loc[df1.year==t-1,"a"]
print(df1)
#    year  a    x
# 0  2020  3  0.0
# 1  2021  4  NaN
# 2  2022  5  NaN
# 3  2023  6  NaN
print(type(df1.loc[df1.year==t-1,"x"] + df1.loc[df1.year==t-1,"a"]))
# <class 'pandas.core.series.Series'>

当等式右边是一个 numpy 数组时,赋值有效

for t in range (min(df1.year)+1, max(df1.year)+1):
    df1.loc[df1.year==t, "x"] = (df1.loc[df1.year==t-1,"x"] + df1.loc[df1.year==t-1,"a"]).unique()
    #break
print(df1)
#    year  a     x
# 0  2020  3   0.0
# 1  2021  4   3.0
# 2  2022  5   7.0
# 3  2023  6  12.0
print(type((df1.loc[df1.year==t-1,"x"] + df1.loc[df1.year==t-1,"a"]).unique()))
# <class 'numpy.ndarray'>

当 .loc() 选择使用年份索引时,分配直接起作用

df2 = df.set_index("year").copy()
# Set the initial value
df2.loc[df2.index.min(), "x"] = 0
for t in range (df2.index.min()+1, df2.index.max()+1):
    df2.loc[t, "x"] = df2.loc[t-1, "x"] + df2.loc[t-1,"a"]
    #break
print(df2)
#       a     x
# year
# 2020  3   0.0
# 2021  4   3.0
# 2022  5   7.0
# 2023  6  12.0
print(type(df2.loc[t-1, "x"] + df2.loc[t-1,"a"]))
# <class 'numpy.float64'>
  • type(df1.loc[df1.year==t-1,"x"] + df1.loc[df1.year==t-1,"a"]) 是一只熊猫 系列,而 type(df2.loc[t-1, "x"] + df2.loc[t-1,"a"]) 是一个 numpy 浮点数。 为什么这些类型不同?
  • 如果我不想在计算前使用set_index()。有没有比使用.unique() 更好的方法来编写递归.loc() 赋值?

另见:

使用乘法和加法组件的示例

我们真正的问题更复杂,因为有一个乘法和一个加法分量

import pandas
df3 = pandas.DataFrame({'year':range(2020,2024),'a':range(3,7), 'b':range(8,12)})
df3 = df3.set_index("year").copy()
# Set the initial value
df3.loc[df3.index.min(), "x"] = 0
for t in range (df3.index.min()+1, df3.index.max()+1):
    df3.loc[t, "x"] = df3.loc[t-1, "x"] * df3.loc[t-1, "a"] + df3.loc[t-1, "b"]
    #break
print(df3)

【问题讨论】:

  • 所以有些递归操作必须使用循环(即一旦达到阈值就重置累积和),然后还有其他递归操作可以 被重写为矢量化操作,通常使用一些shiftexpanding 计算。在您的示例中,递归是一个简单的移位cumsum:df1['x'] = df1['a'].shift().cumsum().fillna(0),但不清楚这是否只是为了 mcve 的简化示例。
  • 感谢您让我走上正确的道路。我过度简化了我的问题中的示例。在我们的实际问题中,有一个乘法和一个加法分量 x_t = a x_{t-1} + b。我应该能够通过在cumprod()cumsum() 之间拆分计算来替换循环,但这可能会使我的同事的代码更加模糊。

标签: python pandas dataframe recursion apply


【解决方案1】:

对不起,如果我不明白,你想要这个吗?

df1['x']= df1['a'].cumsum().shift().fillna(0)
print(df1)

输出:

   year  a     x
0  2020  3   0.0
1  2021  4   3.0
2  2022  5   7.0
3  2023  6  12.0

【讨论】:

  • 真正的问题有一个乘法和一个加法分量 x_t = a x_{t-1} + b。我更新了问题以反映这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-06
  • 2014-11-24
  • 2020-04-03
  • 1970-01-01
  • 2020-03-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多