想象一个滑道和梯子的游戏缩减到两个没有滑道和一个梯子的贴图:
Start: [one] [two] :Finish
梯子可以带你从[1]到Finish,跳过[2]。
当一个棋子(以数字为索引)开始游戏时,我们为它创建一个时间戳。
这是一个有4个棋子的游戏的样子:
In [1]: df
Out[1]:
one two Finish
1 2014-01-01 2014-01-02 2014-01-03
2 2014-01-02 2014-01-06 2014-01-08
3 2014-01-02 NaT 2014-01-05
4 2014-01-02 2014-01-07 2014-01-09
如何将其转换为时间索引的DataFrame,计算每个时间段内每个tile上有多少块?我希望生成的数据框看起来像这样:
In [2]: new_df
Out[2]:
one two
2014-01-01 1 0
2014-01-02 3 1
2014-01-03 3 0
2014-01-04 3 0
2014-01-05 2 0
2014-01-06 1 1
2014-01-07 0 2
2014-01-08 0 1
2014-01-09 0 0
由于我正在处理一个(非常大的,1MM+行,十几列)DataFrame,因此使计算节省将是非常好的。
谢谢!
首先,我认为如果我们通过回填来丢弃NaTs(我们可以这样想,一个片段分成两部分,然后在Finish中立即),这个问题会变得容易一些:
In [11]: df = df.bfill(axis=1)
In [12]: df
Out[12]:
one two Finish
1 2014-01-01 2014-01-02 2014-01-03
2 2014-01-02 2014-01-06 2014-01-08
3 2014-01-02 2014-01-05 2014-01-05
4 2014-01-02 2014-01-07 2014-01-09
现在我们可以使用value_counts
和concat
来获得当前的片段:
In [12]: ones = df['one'].value_counts()
twos = df['two'].value_counts()
finished = df['Finish'].value_counts()
我们必须手动更改名称,因为它们还没有传播(尚未…)。
In [13]: ones.name, twos.name, finished.name = 'one', 'two', 'Finish'
In [14]: counts = pd.concat([ones, twos, finished], axis=1)
In [15]: counts
Out[15]:
one two Finish
2014-01-01 1 NaN NaN
2014-01-02 3 1 NaN
2014-01-03 NaN NaN 1
2014-01-05 NaN NaN 1
2014-01-06 NaN 1 NaN
2014-01-07 NaN 1 NaN
2014-01-08 NaN NaN 1
2014-01-09 NaN NaN 1
In [16]: total = counts.fillna(0).cumsum()
In [17]: total
Out[17]:
one two Finish
2014-01-01 1 0 0
2014-01-02 4 1 0
2014-01-03 4 1 1
2014-01-05 4 2 2
2014-01-06 4 3 2
2014-01-07 4 4 2
2014-01-08 4 4 3
2014-01-09 4 4 4
现在,您可以通过查看列的差异来获得所需的DataFrame:
In [18]: pd.DataFrame({'one': total['one'] - total['two'],
'two': total['two'] - total['Finish']})
Out[18]:
one two
2014-01-01 1 0
2014-01-02 3 1
2014-01-03 3 0
2014-01-05 2 0
2014-01-06 1 1
2014-01-07 0 2
2014-01-08 0 1
2014-01-09 0 0
有可能是一个更简单/更便宜的方法来做到这一点(如果没有,我认为这将使一个很好的功能请求熊猫)…