如何有效地列出(=旋转)pandas DataFrame(with groupby)?

时间:2015-08-26 20:16:25

标签: python pandas

为您提供问题的背景:

我有一个不错的SQL表(72M行,6GB),数据可以理解为"基于列的",例如:

doubleValue()

作为------------------------------ | fk_id | date | field | ------------------------------ | 1 | 2001-01-02 | 24 | | 1 | 2001-01-03 | 25 | | 1 | 2001-01-04 | 21 | | 1 | 2001-01-05 | 20 | | 1 | 2001-01-06 | 30 | | 1 | 2001-01-07 | 33 | | .... | | 2 | 2001-01-02 | 10 | | 2 | 2001-01-03 | 15 | | 2 | 2001-01-04 | 12 | | 2 | 2001-01-05 | 11 | | 2 | 2001-01-06 | 10 | | 2 | 2001-01-07 | 12 | | .... | | .... | | 12455 | 2015-01-01 | 99 | | 12456 | 2005-10-10 | 10 | | 12456 | 2005-10-11 | 10 | | .... | ------------------------------ 的Python中所需的最终结果应该如下所示,其中pandas.DataFrame成为索引列,列名称的外键和列date列的值矩阵:

field

直到现在,我使用以下代码完成此操作:

------------------------------------------------------
| date       |     1 |     2 |  .... | 12455 | 12456 | 
------------------------------------------------------
| 2001-01-02 |    24 |    10 |  .... |   NaN |   NaN |
| 2001-01-03 |    25 |    15 |  .... |   NaN |   NaN |
| 2001-01-04 |    21 |    12 |  .... |   NaN |   NaN |
| 2001-01-05 |    20 |    11 |  .... |   NaN |   NaN |
| 2001-01-06 |    30 |    10 |  .... |   NaN |   NaN |
| 2001-01-07 |    33 |    12 |  .... |   NaN |   NaN |
|       .... |    .. |    .. |  .... |  .... |  .... |
| 2005-10-10 |    50 |     4 |  .... |   NaN |    10 |
| 2005-10-11 |    51 |     3 |  .... |   NaN |    10 |
|       .... |    .. |    .. |  .... |  .... |  .... |
| 2015-01-01 |    40 |   NaN |  .... |    50 |    99 |
------------------------------------------------------

基本上做了:

  1. 直接通过def _split_by_fk(self, df): """ :param df: pandas.DataFrame :param fields: Iterable :return: pandas.Panel """ data = dict() res = df.groupby('fk_id') for r in res: fk_id = r[0] data[fk_id] = r[1]['field'] return pd.DataFrame(data) def get_data(self, start, end): s = select([daily_data.c.date, daily_data.c.fk_id, daily_data.c.field])\ .where(and_(end >= daily_data.c.date, daily_data.c.date >= start))\ .order_by(daily_data.c.fk_id, daily_data.c.date) data = pd.read_sql(s, con=db_engine, index_col='date') return self._split_by_fk(data) >>> get_data('1960-01-01', '1989-12-31') 函数通过sqlalchemy查询SQL DB。
  2. pandas.read_sql收到的groupby
  3. 迭代组结果对象并将它们放在字典中
  4. DataFrame转换为dict
  5. 使用上述方法查询29年813列的29年日常数据4分38秒(整个DataFrame占用内存796.5MB),其中DataFrame表示大部分时间花费在%lprun函数中,其余在read_sql中(输出的摘录):

    _split_by_fk

    我的代码感觉不是很优雅,因为我收集字典中的所有组以将它们再次转换为DataFrame。

    现在我的实际问题是:是否有(更多)高效/ pythonic方式来#34;列化"以上面显示的方式% Time Line Contents =============================================================== 83.8 data = pd.read_sql(s, con=db_engine, index_col='date') 16.2 return self._split_by_fk(data)

    PS:对于处理此类数据结构和数据量的更一般方向,我不满意,但我认为应该可以解决所有问题"小数据&#34 ;式的

2 个答案:

答案 0 :(得分:1)

如果我理解你,你可以df.pivot(index='date', columns='fk_id', values='field')

  

我认为应该可以解决所有“小数据”风格。

祝你好运。具有12000列的DataFrame不太可能表现良好。

答案 1 :(得分:0)

如果fk_iddate的组合始终是唯一的,您可以执行以下操作:

df = pd.DataFrame({'fk_id': [1, 2, 3],
                   'date': pd.date_range('1/1/2015', periods=3),
                   'field': [25, 25, 1]})


#         date  field  fk_id
# 0 2015-01-01     25      1
# 1 2015-01-02     24      2
# 2 2015-01-03      1      3

df.groupby(['date', 'fk_id']).agg(lambda x: x.unique()).unstack()


#            field        
# fk_id          1   2   3
# date                    
# 2015-01-01    25 NaN NaN
# 2015-01-02   NaN  24 NaN
# 2015-01-03   NaN NaN   1

如果它们并不总是唯一的,那么您可能需要一些更复杂的策略来聚合值。