按行数制作的行数相同(对齐观察数)

时间:2018-02-17 23:28:01

标签: python pandas pandas-groupby

我有一个与此类似的数据集:

import pandas as pd
data = pd.DataFrame({'id': [1, 3, 1, 2, 1, 3],
                    'date': ['2018-01-01 10:00', '2018-01-01 10:00', '2018-01-01 11:00',
                             '2018-01-01 11:00', '2018-01-01 12:00', '2018-01-01 12:00']})
data.date = pd.to_datetime(data.date)

输出:

    date                   id
0   2018-01-01 10:00:00     1
1   2018-01-01 10:00:00     3
2   2018-01-01 11:00:00     1
3   2018-01-01 11:00:00     2
4   2018-01-01 12:00:00     1
5   2018-01-01 12:00:00     3

对于每个id,有三个可能的观察点。但是,并非每个点都存在。我想转换数据,使所有ID具有相同数量的观察。应该有一个额外的var,表明观察结果是否原来是空的。我想要的输出是这样的:

    date                   id   empty_obs
0   2018-01-01 10:00:00     1   0
1   2018-01-01 10:00:00     2   1
2   2018-01-01 10:00:00     3   0
3   2018-01-01 11:00:00     1   0
4   2018-01-01 11:00:00     2   0
5   2018-01-01 11:00:00     3   1
6   2018-01-01 12:00:00     1   0
7   2018-01-01 12:00:00     2   1
8   2018-01-01 12:00:00     3   0

目前我唯一的想法是创建一个像这样的DateRange:

period = pd.DataFrame(pd.date_range(data.date.min(), periods=3, freq='H' ))

然后以某种方式将其与分组数据版本合并。但是,这似乎不可能。

我确信那里有一个简单的解决方案。我很感激任何暗示!

2 个答案:

答案 0 :(得分:2)

IIUC

data.assign(empty_obs=0).set_index(['date','id']).unstack().stack(dropna=False).fillna(1).reset_index()
Out[73]: 
                 date  id empty_obs
0 2018-01-01 10:00:00   1    0.0
1 2018-01-01 10:00:00   2    1.0
2 2018-01-01 10:00:00   3    0.0
3 2018-01-01 11:00:00   1    0.0
4 2018-01-01 11:00:00   2    0.0
5 2018-01-01 11:00:00   3    1.0
6 2018-01-01 12:00:00   1    0.0
7 2018-01-01 12:00:00   2    1.0
8 2018-01-01 12:00:00   3    0.0

答案 1 :(得分:2)

您还可以使用groupby + size,然后使用@Wen演示的unstack / stack惯用语:

data.groupby(['date', 'id'])\
    .size()\
    .unstack(fill_value=0)\
    .stack()\
    .reset_index(name='empty_obs')

                 date  id  empty_obs
0 2018-01-01 10:00:00   1          1
1 2018-01-01 10:00:00   2          0
2 2018-01-01 10:00:00   3          1
3 2018-01-01 11:00:00   1          1
4 2018-01-01 11:00:00   2          1
5 2018-01-01 11:00:00   3          0
6 2018-01-01 12:00:00   1          1
7 2018-01-01 12:00:00   2          0
8 2018-01-01 12:00:00   3          1