2016-07-14 107 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