使用pandas将数据分组成单独的批次

3
我正在尝试创建一个函数,将一列批次号添加到一个 DataFrame 中,用于一组时间数据。假设当水平低于/高于1000时,我们已经清空(然后重新填充)了批次,因此这是一个新的批次。这意味着我可以按批次号对数据进行分组以进行进一步分析。
我的数据看起来像:
df_test = pd.DataFrame(
{ 'Time'  : [1300, 1400, 1500, 1600, 1700, 1800],
  'Level' : [ 200, 1300, 1500,  200, 1500, 1400],
  'Data'  : range(6) })

   Data  Level  Time
0     0    200  1300
1     1   1300  1400
2     2   1500  1500
3     3    200  1600
4     4   1500  1700
5     5   1400  1800

我希望它看起来像这样:

   Batch  Data  Level  Time
0    NaN     0    200  1300
1      1     1   1300  1400
2      1     2   1500  1500
3    NaN     3    200  1600
4      2     4   1500  1700
5      2     5   1400  1800

我不关心批次号在批次之间发生什么。 NaN似乎是一个明智的选择,但任何单独和独特的东西都可以。

到目前为止,我尝试做:

df['inUse'] = df['Level'] > 1000

接着尝试着想如何为一列数字编序号,并在每个“真”值处开始一个新的编号,但无法解决。希望得到帮助!谢谢。

编辑

已尝试:

df['Batch'] = (df['Level'] < 1000).cumsum()

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\alarr\Python\WinPython-64bit-2.7.5.3\python-2.7.5.amd64\lib\site-packages\pandas\core\series.py", line 1662, in cumsum
    np.putmask(result, mask, pa.NA)
ValueError: cannot convert float NaN to integer

同时使用Python 2.7.5和Pandas 0.12.0。值得一提的是,我希望将其应用于多达100万行的数据集。我忘记提到这点了!

解决:

我在我的主要数据集上尝试了两种答案,两种都有效!谢谢。出于好奇,我计时了两者,cumsum方法运行时间为0.016秒,而counter运行时间为0.156秒。有趣的是看到两者之间的差异!

2个回答

3

这应该适用于 pandas 0.13 或更高版本:

import pandas as pd
df = pd.DataFrame({ 'Time'  : [1300, 1400, 1500, 1600, 1700, 1800],
                    'Level' : [ 200, 1300, 1500,  200, 1500, 1400],
                    'Data'  : range(6) })
df['Batch'] = (df['Level'] < 1000).cumsum()
print(df)

产出,收益
   Data  Level  Time  Batch
0     0    200  1300      1
1     1   1300  1400      1
2     2   1500  1500      1
3     3    200  1600      2
4     4   1500  1700      2
5     5   1400  1800      2

如果您希望在批次之间得到一个NaN,则可以这样做:
import pandas as pd
import numpy as np
df = pd.DataFrame({ 'Time'  : [1300, 1400, 1500, 1600, 1700, 1800],
                    'Level' : [ 200, 1300, 1500,  200, 1500, 1400],
                    'Data'  : range(6) })

mask = df['Level'] < 1000
df['Batch'] = mask.cumsum()
df.ix[mask, 'Batch'] = np.nan
print(df)

这将产生

   Data  Level  Time  Batch
0     0    200  1300    NaN
1     1   1300  1400      1
2     2   1500  1500      1
3     3    200  1600    NaN
4     4   1500  1700      2
5     5   1400  1800      2

编辑:对于Pandas版本0.12或更早版本曾经存在一个问题与对布尔系列使用cumsum有关。这可能是你看到的错误的来源。如果是这种情况,请在应用cumsum之前将掩码转换为int类型:

mask = (df['Level'] < 1000)
df['Batch'] = mask.astype('int').cumsum()
df.ix[mask, 'Batch'] = np.nan

我刚试过了,得到了如下结果:np.putmask(result, mask, pa.NA) ValueError: 无法将浮点数 NaN 转换为整数 - Alarr
完整的回溯信息非常有用。请再次发布它,最好是在原始帖子中,这样可以更好地格式化。 - unutbu
编辑了我的问题,包括完整的回溯。谢谢。 - Alarr

0

如果你愿意使用全局变量,你可以像这样做。

df = pd.DataFrame({ 'Time'  : [1300, 1400, 1500, 1600, 1700, 1800],
                    'Level' : [ 200, 1300, 1500,  200, 1500, 1400],
                    'Data'  : range(6) })
counter = 0
def handler(x):
    global counter
    if x>1000: return counter
    counter += 1
    return float('nan')

df['Batch'] = df.Level.apply(handler)
print df

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接