您可以尝试以下方法:
1) 获取True 实例(此处为1)的所有值,其中包含isone
2) 获取相应的索引集并将其转换为系列表示,以便新系列具有它的索引和值作为早期计算的索引。执行连续行之间的差异并检查它们是否等于 1。这成为我们的布尔掩码。
3) 将isone 与获得的布尔掩码进行比较,每当它们不相等时,我们就取它们的累积和(也称为元素之间的邻接检查)。这些有助于我们进行分组。
4) 使用loc 作为isone 的索引,我们将在将grp 数组更改为分类格式后计算的代码分配给创建的新列Event_number。
isone = df.Bolean_condition[df.Bolean_condition.eq(1)]
idx = isone.index
grp = (isone != idx.to_series().diff().eq(1)).cumsum()
df.loc[idx, 'Event_number'] = pd.Categorical(grp).codes + 1
更快的方法:
仅使用numpy:
1) 获取它的数组表示。
2) 计算非零,此处为 (1's) 索引。
3) 在这个数组的开头插入NaN,这将作为我们在考虑连续行的情况下执行差异的起点。
4) 初始化一个用Nan's 填充的新数组,其形状与原数组相同。
5) 每当连续行之间的差不等于 1 时,我们取它们的累积和,否则它们属于同一组。这些值在之前有 1's 的索引处进行估算。
6) 将这些分配回新列。
def nick(df):
b = df.Bolean_condition.values
slc = np.flatnonzero(b)
slc_pl_1 = np.append(np.nan, slc)
nan_arr = np.full(b.size, fill_value=np.nan)
nan_arr[slc] = np.cumsum(slc_pl_1[1:] - slc_pl_1[:-1] != 1)
df['Event_number'] = nan_arr
return df
时间安排:
对于 10,000 行的 DF:
np.random.seed(42)
df1 = pd.DataFrame(dict(
Timestamp=np.arange(10000),
Bolean_condition=np.random.choice(np.array([0,1]), 10000, p=[0.4, 0.6]))
)
df1.shape
# (10000, 2)
def jez(df):
mask0 = df.Bolean_condition.eq(0)
mask2 = df.Bolean_condition.ne(df.Bolean_condition.shift(1))
df['Event_number'] = (mask2 & mask0).cumsum().mask(mask0)
return (df)
nick(df1).equals(jez(df1))
# True
%%timeit
nick(df1)
1000 loops, best of 3: 362 µs per loop
%%timeit
jez(df1)
100 loops, best of 3: 1.56 ms per loop
对于包含 100 万行的 DF:
np.random.seed(42)
df1 = pd.DataFrame(dict(
Timestamp=np.arange(1000000),
Bolean_condition=np.random.choice(np.array([0,1]), 1000000, p=[0.4, 0.6]))
)
df1.shape
# (1000000, 2)
nick(df1).equals(jez(df1))
# True
%%timeit
nick(df1)
10 loops, best of 3: 34.9 ms per loop
%%timeit
jez(df1)
10 loops, best of 3: 50.1 ms per loop