2016-07-14 144 views
2

我有以下形式拆分嵌套數組值

enter image description here

有每年(2008年至2015年)每ID一行的Pandas DataFrame。對於Max TempMin TempRain每個單元包含對應於一天在這一年值的陣列,即,對於上述

  • frame3.iloc[0]['Max Temp'][0]該幀的列是用於2011年1月1日
  • frame3.iloc[0]['Max Temp'][364]值的值對於2011年12月31日。

我知道這是嚴重的結構,但這是我必須處理的數據。它以這種方式存儲在MongoDB中(其中一行等同於Mongo中的文檔)。

我想拆分這些嵌套數組,以便每個ID每年有一行,而不是每個ID每天一行。然而,在分割數組的同時,我還想根據當前的數組索引創建一個新列以捕捉一年中的某一天。然後我會用這一天,再加上Year列創建DatetimeIndex

enter image description here

我搜索這裏相關的答案,但只找到this one它並沒有真正幫助我。

+0

這些內部數組表示爲字符串還是實數組? – ptrj

+0

他們是漂浮物列表 –

回答

4

您可以爲每個列運行.apply(pd.Series),然後stack並連接結果。

對於一系列

s = pd.Series([[0, 1], [2, 3, 4]], index=[2011, 2012]) 

s 
Out[103]: 
2011  [0, 1] 
2012 [2, 3, 4] 
dtype: object 

其工作原理如下

s.apply(pd.Series).stack() 
Out[104]: 
2011 0 0.0 
     1 1.0 
2012 0 2.0 
     1 3.0 
     2 4.0 
dtype: float64 

系列的元素有不同的長度(這很重要,因爲2012年是閏年)。中間系列,即在stack之前具有後來被丟棄的NaN值。

現在,讓我們一幀:

a = list(range(14)) 
b = list(range(20, 34)) 

df = pd.DataFrame({'ID': [11111, 11111, 11112, 11112], 
        'Year': [2011, 2012, 2011, 2012], 
        'A': [a[:3], a[3:7], a[7:10], a[10:14]], 
        'B': [b[:3], b[3:7], b[7:10], b[10:14]]}) 

df 
Out[108]: 
        A     B  ID Year 
0   [0, 1, 2]  [20, 21, 22] 11111 2011 
1  [3, 4, 5, 6] [23, 24, 25, 26] 11111 2012 
2   [7, 8, 9]  [27, 28, 29] 11112 2011 
3 [10, 11, 12, 13] [30, 31, 32, 33] 11112 2012 

然後我們可以運行:

# set an index (each column will inherit it) 
df2 = df.set_index(['ID', 'Year']) 
# the trick 
unnested_lst = [] 
for col in df2.columns: 
    unnested_lst.append(df2[col].apply(pd.Series).stack()) 
result = pd.concat(unnested_lst, axis=1, keys=df2.columns) 

,並得到:

result 
Out[115]: 
       A  B 
ID Year    
11111 2011 0 0.0 20.0 
      1 1.0 21.0 
      2 2.0 22.0 
     2012 0 3.0 23.0 
      1 4.0 24.0 
      2 5.0 25.0 
      3 6.0 26.0 
11112 2011 0 7.0 27.0 
      1 8.0 28.0 
      2 9.0 29.0 
     2012 0 10.0 30.0 
      1 11.0 31.0 
      2 12.0 32.0 
      3 13.0 33.0 

其餘(日期時間指數)更那麼簡單。例如:

# DatetimeIndex 
years = pd.to_datetime(result.index.get_level_values(1).astype(str)) 
# TimedeltaIndex 
days = pd.to_timedelta(result.index.get_level_values(2), unit='D') 
# If the above line doesn't work (a bug in pandas), try this: 
# days = result.index.get_level_values(2).astype('timedelta64[D]') 

# the sum is again a DatetimeIndex 
dates = years + days 
dates.name = 'Date' 

new_index = pd.MultiIndex.from_arrays([result.index.get_level_values(0), dates]) 

result.index = new_index 

result 
Out[130]: 
        A  B 
ID Date     
11111 2011-01-01 0.0 20.0 
     2011-01-02 1.0 21.0 
     2011-01-03 2.0 22.0 
     2012-01-01 3.0 23.0 
     2012-01-02 4.0 24.0 
     2012-01-03 5.0 25.0 
     2012-01-04 6.0 26.0 
11112 2011-01-01 7.0 27.0 
     2011-01-02 8.0 28.0 
     2011-01-03 9.0 29.0 
     2012-01-01 10.0 30.0 
     2012-01-02 11.0 31.0 
     2012-01-03 12.0 32.0 
     2012-01-04 13.0 33.0 
+0

優秀的答案,謝謝。你是對的,'days = pd.to_timedelta(result.index.get_level_values(2),unit ='D')'不起作用,我需要你提供的選項'days = result.index.get_level_values(2)。 astype('timedelta64 [D]')' –

+1

很高興我能幫上忙。使'to_timedelta'中斷的錯誤將在下一個熊貓發行版中解決。 – ptrj