Python 根据其他字段重新计算数据帧字段的更好方法
我是新来的。 考虑到费用和一段时期内的增长情况,我想估算长期内的流入付款价值。 我只使用了一次付款(流入)进行测试。 有时fee2可以应用到周期n-t。i、 e.不是整个时期,n 我是这样做的,只是想知道是否有更好的方法可以在不循环的情况下重新计算值 电子表格中的示例: Python代码:Python 根据其他字段重新计算数据帧字段的更好方法,python,python-3.x,pandas,numpy,Python,Python 3.x,Pandas,Numpy,我是新来的。 考虑到费用和一段时期内的增长情况,我想估算长期内的流入付款价值。 我只使用了一次付款(流入)进行测试。 有时fee2可以应用到周期n-t。i、 e.不是整个时期,n 我是这样做的,只是想知道是否有更好的方法可以在不循环的情况下重新计算值 电子表格中的示例: Python代码: import pandas as pd import numpy as np def getCashFlows(): term = 2 growthRate = (1+0.06)**(1/12
import pandas as pd
import numpy as np
def getCashFlows():
term = 2
growthRate = (1+0.06)**(1/12) - 1
df = pd.DataFrame(list(range(1,term*12+1)), columns=['t'])
df['Value_t_1'] = 0
df['Inflow1']=0
df['growth']=0
df['ValuePlusGrowth'] = 0
df['fee1']=0
df['fee2']=30
df['Value_t']=0
df.set_value(0, 'Inflow1', 10000)
for i in range(0,term*12):
df['Value_t_1'] = df['Value_t'].shift()
df['Value_t_1'].fillna(0,inplace=True)
df['growth'] = (df['Value_t_1'] + df['Inflow1'])*growthRate
df['ValuePlusGrowth'] = df['Value_t_1']+df['Inflow1']+df['growth']
df['fee1']=df['ValuePlusGrowth']*0.5/100
df['Value_t'] = df['ValuePlusGrowth'] - df['fee1'] - df['fee2']
return df
真正需要的唯一初始输入是流入的初始值。根据行索引,其他所有操作都可以简化为重复一定次数的操作。数据框中的一些列实际上只是常量 下面是一个解决方案,它阐明了计算数据帧的每一行所需的操作:
import pandas as pd
class GrowthTracker(object):
def __init__(self, n_iter):
self.colnames = ['Value_t_1', 'growth', 'ValuePlusGrowth', 'fee1', 'Value_t']
self.data = None
self.fee1_mult = 0.5/100
self.fee2 = (0,0,0,0,30)
self.growthRate = (1+0.06)**(1/12) - 1
self.n_iter = n_iter
self.ops = pd.Series([1, # Value_t_1
self.growthRate, # growth
(1 + self.growthRate), # ValuePlusGrowth
(1 + self.growthRate) * self.fee1_mult, # fee1
(1 + self.growthRate) * (1 - self.fee1_mult) # Value_t
])
def update(self, t, n, df=None):
row = self.ops.mul(t).subtract(self.fee2)
tmp = pd.concat([df, row], axis = 1, ignore_index=True)
if n < self.n_iter:
self.data = self.update(row.iloc[-1], n+1, tmp)
return self.data
else:
tmp.iloc[0,0] = 0 # remove the initial 10000 from Value_t_1
self.data = tmp.T
self.data.columns = self.colnames
return self.data
我发现将这一切表示为一个类比较容易,但只需在类之外定义变量,然后运行update()
函数就足够简单了
更新以下是此解决方案背后的更多解释: 初始数据帧
df
大部分为空。唯一完全非零的列是从不使用的t
,以及fee2
,这是一个常量(fee2=30
)。df
的整个剩余部分开始时为零值,只有Inflow1
中的第一个单元格例外-其第一个值为10000
,其余值为零
这意味着,就我们需要完成的计算而言,我们可以将“兴趣矩阵”限制在列Value\u t\u 1
、growth
、ValuePlusGrowth
、fee1
和Value\u t
我们可以将第一个Inflow1
值视为种子-其他一切都只是对数字10000
执行的一系列操作。(事实上,我们实际上不需要将Inflow1
作为字段,因为它的所有其他值在整个计算过程中都保持为零。)
在循环中,最初使用其他列的值更新列。这是有道理的,我可能也会这么做——看起来整洁高效。然而,回想一下,每一次更新实际上只是一个数学字符串,将其沿袭追溯到原始的10000
。写出每个列更新的实际操作,而不是使用其他列名,说明如何简化每个更新操作
首先,一些速记符号:
t = Value_t from previous row (in case of the first row, Value_t = Inflow1 = 10000)
t1 = Value_t_1
g = growth
inf = Inflow1
vpg = ValuePlusGrowth
gr = growthRate # gr is a constant: (1+0.06)**(1/12) - 1
f1X = 0.5/100
new_t = Value_t for current row
我们从t=10000开始。其他一切都是对t
的操作
每一个值都可以用我们需要乘以的值来表示,以得到所需的值(后面我将讨论一个例外)。例如:
df['Value_t_1'] = df['Value_t'].shift()
df['Value_t_1'].fillna(0,inplace=True)
# equivalent to:
t1 = 1 * t # recall t is the shifted Value_t from the previous row
请记住,我们只需要输入种子值t
一次,然后只需对种子执行操作即可填充所有df
。这意味着循环中的操作可以表示为“需要乘以t才能得到正确列值的项”。因此,尽管我们已经证明了t1=1*t
,但我们更应该考虑t1=1
——最终我们会将其乘以t
,但等式的右侧表示t1
与t
的关系
然后:
下一步:
现在,对于每一行,我们为每一列提供了一组更新操作ops
。假设我们有上一行的t
,我们可以用以下内容填充每一行的值:
new_row = t * ops
我们仍然需要从new\u t
中减去fee2
,而这并不完全符合到目前为止的一系列乘法运算。但我们可以坚持我们的矢量化公式并定义:
fee2 = (0,0,0,0,30)
在每个new\u row
之后,我们从new\u row
向量中减去fee2
向量,这实际上只是根据需要从new\u t
中减去fee2
new_row = t * ops - fee2
此时,我们只需要一个函数,它以t=10000
开始,并继续执行new_row
公式,建立在前一行的基础上,直到达到所需的迭代次数。为此,我选择了一种递归策略,并在每个递归步骤中将每个新行
保存到一个数据帧中
最后,由于我设置了
t=10000
而不是Inflow1=10000
,这意味着第一个t1
值被错误地设置为10000
。在update()
函数的末尾,我们将第一个t1
值设置回0
只需去掉def&for并运行其余的代码。循环是隐含的。您有“for i”,但没有“i”,所以您所做的只是重复完全相同的代码24次,而不是一次,并且它在整个df上每隔一天运行一次time@JohnE-实际上不完全是。起初我也这么想,但注意到第一行中的shift()
。每个循环都在值上向前看。在这样做的过程中,OP实际上是在24个周期内累积这些值。谢谢@andrew_reece,但我正在努力运行代码,我在引用一些变量之前修复了其他简单错误,例如缺少self…但是对update(self,t,n,df=None)、update(row.iloc[-1],n+1,self.n_iter,tmp)的递归调用有一个额外的值(row.iloc[-1])对此我很抱歉,在我转换为基于类的方法之前,我的环境中有一些变量,在我发布之前,我没有清除所有要测试的内容。是我的错。现在更新了,我已经从一个新的内核开始了这段代码,并确认一切都正常工作。非常感谢…花了更长的时间,因为我想确保我理解它…不客气,我真的很喜欢这个挑战。我补充说
new_row = t * ops
fee2 = (0,0,0,0,30)
new_row = t * ops - fee2