【问题标题】:Split nested array values from Pandas Dataframe cell over multiple rows将 Pandas Dataframe 单元格中的嵌套数组值拆分为多行
【发布时间】:2016-11-17 05:48:09
【问题描述】:

我有一个Pandas DataFrame,格式如下

每年(2008 - 2015 年)每个 ID 有一行。对于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

我在这里搜索了相关答案,但只找到了this one,这对我没有帮助。

【问题讨论】:

  • 这些内部数组是表示为字符串还是实数组?
  • 它们是浮动列表

标签: python numpy pandas dataframe


【解决方案1】:

您可以为每个列运行 .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

【讨论】:

  • 很好的答案,谢谢。你说得对,days = pd.to_timedelta(result.index.get_level_values(2), unit='D') 不起作用,我需要你提供的替代方法 days = result.index.get_level_values(2).astype('timedelta64[D]')
  • 很高兴我能帮上忙。导致to_timedelta 崩溃的错误将在下一个 pandas 版本中修复。
猜你喜欢
  • 1970-01-01
  • 2021-06-26
  • 2016-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多