根据其他字段重新计算pandas数据帧字段的更好方法

2024-09-28 01:24:30 发布

您现在位置:Python中文网/ 问答频道 /正文

我不熟悉Python熊猫。 我想估算一个时期内流入付款的价值,考虑到费用和一段时期内的增长。 我只使用了一次付款(流入)来测试。 有时fee2可以应用到n-t周期,即不是整个周期,n

我像下面这样做,只是想知道是否有更好的方法来重新计算值而不循环?在

电子表格示例: enter image description here

Python代码:

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

Tags: importdfvalueasrangepd费用价值
1条回答
网友
1楼 · 发布于 2024-09-28 01:24:30

真正需要的唯一初始输入是inflow的初始值。其他所有操作都可以简化为基于行索引重复一定次数的操作。数据框中的一些列实际上只是常量。在

下面是一个解决方案,它阐明了计算数据帧的每一行所需的操作:

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

现在只需设置初始值,实例化GrowthTracker对象,update()

^{pr2}$

我发现将这些都表示为一个类比较容易,但是只要在类之外定义变量,然后运行update()函数就足够简单了。在

更新
以下是这个解决方案背后的更多解释:

初始数据帧df大部分是空的。唯一完全非零的列是t,它从未使用过,和fee2,它是一个常量(fee2 = 30)。df的其余部分以零值开始,除了Inflow1中第一个单元格的一个例外,它的第一个值是10000,其余的值都是零。在

这意味着,就我们需要完成的计算而言,我们可以将“兴趣矩阵”限制为列Value_t_1growthValuePlusGrowthfee1、和{}。在

我们可以把第一个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的一些操作。在

每个值都可以表示为我们需要将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与{}的关系。在

然后:

t1 = 1

下一步:

# Inflow1 is always 0, except for its initial value which we capture in initial t, so:
df['growth'] = (df['Value_t_1'] + df['Inflow1'])*growthRate
# becomes:
g = t1 * gr 
# with t1 = 1
g = gr

# we know t1 = 1, and inf is never used as a multiplier, so:
df['ValuePlusGrowth'] = df['Value_t_1']+df['Inflow1']+df['growth']
# becomes:
vpg = 1 + g = 1 + gr

df['fee1']=df['ValuePlusGrowth']*0.5/100
# becomes:
fee1 = vpg * f1X = (1 + gr) * f1X

# we'll ignore subtracting fee2 for now, see notes below.
df['Value_t'] = df['ValuePlusGrowth'] - df['fee1'] - df['fee2']
# becomes:
new_t = vpg - fee1 = (1 + gr) - ((1 + gr) * f1X) = (1 + gr) * (1 - f1X)

ops = (t1, g, vpg, fee1, new_t)

现在,对于每一行,我们对每一列都有一组更新操作ops。假设我们有上一行的t,我们可以用以下内容填充每一行的值:

new_row = t * ops

我们仍然需要从new_t中减去fee2,而这并不能很好地适用于到目前为止,一系列的乘法运算。但我们可以坚持矢量化公式并定义:

fee2 = (0,0,0,0,30)

在每个new_row之后,我们从new_row向量中减去{}向量,这实际上只是根据需要从new_t中减去{}。在

new_row = t * ops - fee2

此时,我们只需要一个以t = 10000开头的函数,在前面的每一行上继续执行new_row公式,直到达到所需的迭代次数。我选择了一个递归策略来实现这一点,并在每个递归步骤将每个new_row保存到一个数据帧中。在

最后,由于我将t = 10000设置为t,这意味着第一个t1值不正确直接设置在10000。在update()函数的末尾,我们将第一个t1值设置回0。在

相关问题 更多 >

    热门问题