Python 使按列分组的行数相同(对齐观察数)

Python 使按列分组的行数相同(对齐观察数),python,pandas,pandas-groupby,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 1

我有一个类似的数据集:

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都在每个点上出现。我希望转换数据,使所有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
目前我唯一的想法是创建如下日期范围:

period = pd.DataFrame(pd.date_range(data.date.min(), periods=3, freq='H' ))
然后以某种方式将其与按版本分组的数据合并。然而,这似乎是不可能的

我相信有一个简单的解决办法。如果有任何提示,我将不胜感激

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
IIUC


您还可以使用
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

您还可以使用
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

您可以绕过fillna以获得更高性能的答案:
数据。设置索引(['date',id'])。分配(空的\u obs=1)。取消堆栈(-1,fill\u value=0)。堆栈()。重置\u索引()
@cᴏʟᴅsᴘᴇᴇᴅ 是的,这是很大的改进:-)添加了与groupby类似的内容。干杯:)你可以绕过fillna获得更高性能的答案:
数据。设置索引(['date',id'])。分配(空的\u obs=1)。取消堆栈(-1,fill\u value=0)。堆栈()。重置\u索引()
@cᴏʟᴅsᴘᴇᴇᴅ 是的,这是很大的改进:-)添加了与groupby类似的内容。干杯:)