<p><strong>有关更可靠的解决方案,请参阅EDIT2</strong></p>
<p>同样的结果,但速度要快一点:</p>
<pre class="lang-python prettyprint-override"><code>labels = (df.value != df.value.shift()).cumsum()
df['flag'] = (labels.map(labels.value_counts()) >= 3).astype(int)
id value flag
0 1 2 0
1 1 2 0
2 1 3 0
3 1 2 1
4 1 2 1
5 1 2 1
6 1 3 1
7 1 3 1
8 1 3 1
9 1 3 1
10 2 1 0
11 2 4 0
12 2 1 1
13 2 1 1
14 2 1 1
15 2 4 0
16 2 4 0
17 2 1 1
18 2 1 1
19 2 1 1
20 2 1 1
21 2 1 1
</code></pre>
<p>其中:</p>
<ol>
<li><code>df.value != df.value.shift()</code>给出值的变化</li>
<li><code>cumsum()</code>为每个值相同的组创建“标签”</li>
<li><code>labels.value_counts()</code>统计每个标签的出现次数</li>
<li><code>labels.map(...)</code>用上面计算的计数替换标签</li>
<li><code>>= 3</code>在计数值上创建布尔掩码</li>
<li><code>astype(int)</code>将布尔值转换为int</li>
</ol>
<p>在我的手中,你的df值是1.03毫秒,而灵能症治疗的df值是2.1毫秒。
但我的不是一艘班轮。</p>
<hr/>
<p>编辑:</p>
<p>两种方法的混合甚至更快</p>
<pre class="lang-python prettyprint-override"><code>labels = df.value.diff().ne(0).cumsum()
df['flag'] = (labels.map(labels.value_counts()) >= 3).astype(int)
</code></pre>
<p>提供911微秒的样品测向。</p>
<hr/>
<p>EDIT2:正确的解决方案来解释id更改,如@clg4所示</p>
<pre class="lang-python prettyprint-override"><code>labels = (df.value.diff().ne(0) | df.id.diff().ne(0)).cumsum()
df['flag'] = (labels.map(labels.value_counts()) >= 3).astype(int)
</code></pre>
<p>其中<code>... | df.id.diff().ne(0)</code>增加id更改的标签</p>
<p>即使在id更改时使用相同的值(在索引10中使用值3进行测试),也可以使用1.28ms</p>
<p>EDIT3:更好的解释</p>
<p>以索引10的值为3的情况为例。<code>df.id.diff().ne(0)</code></p>
<pre class="lang-python prettyprint-override"><code>data={'id':[1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2],
'value':[2,2,3,2,2,2,3,3,3,3,3,4,1,1,1,4,4,1,1,1,1,1]}
df=pd.DataFrame.from_dict(data)
df['id_diff'] = df.id.diff().ne(0).astype(int)
df['val_diff'] = df.value.diff().ne(0).astype(int)
df['diff_or'] = (df.id.diff().ne(0) | df.value.diff().ne(0)).astype(int)
df['labels'] = df['diff_or'].cumsum()
id value id_diff val_diff diff_or labels
0 1 2 1 1 1 1
1 1 2 0 0 0 1
2 1 3 0 1 1 2
3 1 2 0 1 1 3
4 1 2 0 0 0 3
5 1 2 0 0 0 3
6 1 3 0 1 1 4
7 1 3 0 0 0 4
8 1 3 0 0 0 4
9 1 3 0 0 0 4
>10 2 3 1 | 0 = 1 5 <== label increment
11 2 4 0 1 1 6
12 2 1 0 1 1 7
13 2 1 0 0 0 7
14 2 1 0 0 0 7
15 2 4 0 1 1 8
16 2 4 0 0 0 8
17 2 1 0 1 1 9
18 2 1 0 0 0 9
19 2 1 0 0 0 9
20 2 1 0 0 0 9
21 2 1 0 0 0 9
</code></pre>
<p><code>|</code>是运算符“按位或”,只要其中一个元素是<code>True</code>,它就给出<code>True</code>。因此,如果id更改的值中没有diff,则<code>|</code>反映id更改。否则什么也改变不了。
当执行<code>.cumsum()</code>时,如果id发生变化,标签将递增,因此索引10处的值<code>3</code>不会与索引6-9中的值<code>3</code>分组。</p>