2017-08-30 83 views
2

我有以下pd數據幀。Pandas在列間插入日期

import pandas as pd 

df = pd.DataFrame([pd.datetime(2016,1,1), pd.datetime(2016,2,1)], columns = ['d1']) 
df['d2'] = [pd.datetime(2016,1,5), pd.datetime(2016,2,10)] 
df['d3'] = [pd.datetime(2016,1,10), pd.datetime(2016,2,20)] 
df['v1'], df['v2'], df['v3'] = [1,10], [5, 100], [5, 100] 
df['x1'] = [pd.datetime(2016,1,2), pd.datetime(2016,2,13)] 


      d1   d2   d3 v1 v2 v3   x1 
0 2016-01-01 2016-01-05 2016-01-10 1 5 5 2016-01-02 
1 2016-02-01 2016-02-10 2016-02-20 10 100 100 2016-02-13 

我想通過內插

x: x1 
independent = [d1, d2, d3] 
dependent = [v1, v2, v3] 

在上面的例子來計算列X2,X2應該是2行0,100爲第1行

我能想到使用df.iterrows(),slice [d1-d3]和[v1-v3],然後使用np.interp,但即使這樣會變得有點複雜,因爲我必須將日期轉換爲float。 (np.interp只接受浮動列表)。

熊貓內應該有一個更清潔,矢量化的方法嗎?

回答

1

我不知道Pandas是否可以使用特定列作爲IV和DV進行插值。但是,如果將時間戳視爲單個系列,則可以獲得所需的內容。

稍加改動後,我們可以重新格式化interpolate(method='time')的數據框,然後將其恢復爲原始格式。與您的樣本數據幀開始,加上一個空x2

import numpy as np 
df['x2'] = np.nan 

df 
      d1   d2   d3 v1 v2 v3   x1 x2 
0 2016-01-01 2016-01-05 2016-01-10 1 5 5 2016-01-02 NaN 
1 2016-02-01 2016-02-10 2016-02-20 10 100 100 2016-02-13 NaN 

現在從寬擺長,並凝結成只有兩列,dvx獲得榮譽會員在dv俱樂部現在)。保存的實際列名稱作爲索引:

pairs = [('d1','v1'), ('d2','v2'), ('d3','v3'), ('x1','x2')] 
df2 = pd.concat(
    (df[[d, v]].rename(index=lambda i: d, 
         columns=lambda x: 'd' if (x[0]=='d') | (x=='x1') else 'v') for d, v in pairs)) 

df2 

      d  v 
d1 2016-01-01 1.0 
d1 2016-02-01 10.0 
d2 2016-01-05 5.0 
d2 2016-02-10 100.0 
d3 2016-01-10 5.0 
d3 2016-02-20 100.0 
x1 2016-01-02 NaN 
x1 2016-02-13 NaN 

我們要基於時間interpolate,因此我們將繼續前進時間戳到索引,按日期排序,然後進行插值:

df3 = (df2.reset_index() 
      .set_index(pd.to_datetime(df2.d)) 
      .drop('d', 1) 
      .sort_index() 
      .interpolate(method="time") 
      .sort_values('index') 
    ) 

df3 
      index  v 
d      
2016-01-01 d1 1.0 
2016-02-01 d1 10.0 
2016-01-05 d2 5.0 
2016-02-10 d2 100.0 
2016-01-10 d3 5.0 
2016-02-20 d3 100.0 
2016-01-02 x1 2.0 
2016-02-13 x1 100.0 

每個OP預期輸出的插值是正確的。現在我們只需要將數據框恢復到原始形狀。我們這樣做是通過設置索引回0/1的基礎上,奇/偶行號,然後使用pivot()

df4 = df3.reset_index().rename(index=lambda x: int(x%2)).pivot(columns='index') 
df4.columns = df4.columns.droplevel(0) 
iv, dv = zip(*pairs) 
df4.columns = iv + dv 

df4 
      d1   d2   d3   x1 v1  v2  v3  x2 
0 2016-01-01 2016-01-05 2016-01-10 2016-01-02 1.0 5.0 5.0 2.0 
1 2016-02-01 2016-02-10 2016-02-20 2016-02-13 10.0 100.0 100.0 100.0 

有可能重塑在中間的東西隱蔽的方式,但關鍵的直覺如果給出正確的格式,熊貓將使用時間作爲參考插入缺失值。

UPDATE(每評論)
如果內插必須每行發生,我們可以使用一個類似的方法如上述,與apply()

def custom_interp(row, pairs): 
    data = pd.concat(
     (pd.DataFrame(row[[d, v]]).rename(index=lambda x: 'd' if (x[0] == 'd') | (x == 'x1') else 'v', 
              columns=lambda x: d) for d, v in pairs), 
     axis=1).T.reset_index() 
    data = (data.set_index(pd.to_datetime(data.d)) 
       .drop('d', 1) 
       .sort_index() 
      ) 
    data.v = data.v.astype(float) 
    data = data.interpolate(method='time').reset_index() 
    data.index = np.repeat(row.name, len(data.index)) 
    data = data.pivot(columns='index') 
    data.columns = data.columns.droplevel(0) 
    return data.values[0] 

df.apply(custom_interp, args=(pairs,), axis=1) 

      d1   d2   d3   v1 v2  v3  x1  x2 
0 2016-01-01 2016-01-05 2016-01-10 2016-01-02 1.0 5.0 5.0 2.0 
1 2016-02-01 2016-02-10 2016-02-20 2016-02-13 10.0 100.0 100.0 100.0 
+0

感謝。就像這個想法一樣,但是插值需要按行進行。您的示例df2將d行和v行結合在一起。 –

+0

在您提供的示例數據中,每行中的日期形成了不跨行的時段。您的數據中是否會出現這種重疊情況? –

+0

是的,對不起,我的例子很差。有重疊。更好的例子是在第1行中將所有'Feb'替換爲'Jan'。 –

相關問題