2017-08-13 38 views
2

我是新的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 
+0

剛剛擺脫def&for並運行其餘的代碼。循環是隱含的。你有「爲我」,但沒有「我」,所以你所做的只是重複完全相同的代碼24次而不是一次,它每次都在整個DF上運行 – JohnE

+1

@JohnE - 實際上並不完全。起初,我認爲是相同的,但注意第一行中的「shift()」。每個循環都在* Value_t *上向前看。而這樣做,OP實際上是在24個時期內積累這些價值。 – Parfait

回答

2

真正需要的是用於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()

total_iter = 23 

tracker = GrowthTracker(n_iter=total_iter) 

inflow = 10000 
start_index = 0 

tracker.update(t=inflow, n=start_index) 

tracker.data 

     Value_t_1  growth ValuePlusGrowth  fee1  Value_t 
0  0.000000 48.675506  10048.675506 50.243378 9968.432128 
1 9968.432128 48.521847  10016.953976 50.084770 9936.869206 
2 9936.869206 48.368213  9985.237419 49.926187 9905.311232 
3 9905.311232 48.214603  9953.525835 49.767629 9873.758206 
4 9873.758206 48.061017  9921.819223 49.609096 9842.210127 
5 9842.210127 47.907455  9890.117583 49.450588 9810.666995 
6 9810.666995 47.753918  9858.420912 49.292105 9779.128808 
7 9779.128808 47.600404  9826.729212 49.133646 9747.595566 
8 9747.595566 47.446914  9795.042480 48.975212 9716.067268 
9 9716.067268 47.293449  9763.360716 48.816804 9684.543913 
10 9684.543913 47.140007  9731.683920 48.658420 9653.025500 
11 9653.025500 46.986590  9700.012090 48.500060 9621.512030 
12 9621.512030 46.833196  9668.345226 48.341726 9590.003500 
13 9590.003500 46.679827  9636.683327 48.183417 9558.499910 
14 9558.499910 46.526482  9605.026392 48.025132 9527.001260 
15 9527.001260 46.373160  9573.374420 47.866872 9495.507548 
16 9495.507548 46.219863  9541.727411 47.708637 9464.018774 
17 9464.018774 46.066590  9510.085364 47.550427 9432.534937 
18 9432.534937 45.913341  9478.448278 47.392241 9401.056037 
19 9401.056037 45.760116  9446.816152 47.234081 9369.582072 
20 9369.582072 45.606915  9415.188986 47.075945 9338.113041 
21 9338.113041 45.453737  9383.566779 46.917834 9306.648945 
22 9306.648945 45.300584  9351.949529 46.759748 9275.189781 
23 9275.189781 45.147455  9320.337237 46.601686 9243.735551 

我發現將它們全部表述爲一個類更容易,但它足夠簡單,只需在類之外定義變量,然後運行update()函數即可。

UPDATE
下面是該解決方案的背後更多的解釋:

初始數據幀df大部分是空的。唯一完全非零的列是從未使用的tfee2,這是一個常數(fee2 = 30)。 df的整個剩餘部分以零值開始,除Inflow1中的第一個單元外 - 其第一個值爲10000,其餘值爲零。

這意味着,在我們所需要完成的計算而言,我們可以限制我們的「利益矩陣」的列Value_t_1growthValuePlusGrowthfee1Value_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上進行一些操作。

每個值都可以用我們需要乘以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,但該等式的右邊代表t1t的關係。

然後:

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載體,無論你希望真的只是減去fee2new_tfee2載體。

new_row = t * ops - fee2 

在這一點上,我們只需要與t = 10000開始並保持執行new_row公式,建立在每一個上一行的功能,直到我們達到我們所期望的迭代次數。我選擇了一個遞歸策略來做到這一點,並在每個遞歸步驟中將每個new_row保存到數據幀中。

最後,因爲我有點通過設置t = 10000而不是Inflow1 = 10000濫用你原來的符號,這意味着第一t1值不正確地設置爲10000。在update()函數結束時,我們將第一個t1值設置回0

+0

感謝@andrew_reece,但我努力運行代碼,我修復了其他簡單的錯誤,如在引用一些變量之前丟失self ...但是遞歸調用update(self,t,n,df = None),update(row。 iloc [-1],n + 1,self.n_iter,tmp)有一個額外的值(row.iloc [-1])我不能匹配 – Mosd

+0

對不起,我有一些變量在我的環境中到基於班級的方法,而且在發佈之前我沒有清楚所有要測試的內容。我的錯。現在更新了,我從一個新的內核開始了這段代碼,並確認所有內容都以發佈的方式工作。 –

+0

非常感謝...花了更長的時間,因爲我想確保我明白了... – Mosd