检测三次相等元素列表的高效函数
Efficient function to detect a list of thrice equal elements
我正在寻找一种有效的函数来找到至少连续出现三次且不间断的标记。
输入示例:
import pandas as pd
marks = [83, 79, 83, 83, 83, 79, 79, 83]
student_id = [101, 102, 103, 104, 105, 106, 107, 108]
d = {'student_id':student_id,'marks':marks}
df = pd.DataFrame (d)
期望的输出:
83
如果可能的话,我正在寻找比使用 for
循环跟踪前 2 个标记的逐行循环更有效的方法。也就是说,我正在寻找比以下更好的东西:
def thrice_f (marks, number_of_apperances):
cache = marks[0]
counter = 1
for mark in marks[1:]:
if mark == cache:
counter += 1
if counter == number_of_apperances:
return cache
else:
counter = 1
cache = mark
是的,您可以使用 itertools.groupby()
:
from itertools import groupby
result = [key for key, group in groupby(marks) if len(list(group)) >= 3]
print(result)
这将给出连续出现超过 3 次的所有元素的列表:
[83]
如果你知道只有一个这样的组存在,你可以使用列表解包来提取单个元素:
[result] = [key for key, group in groupby(marks) if len(list(group)) >= n]
这输出:
83
另一个解决方案,仅使用 pandas
:
x = (
df.groupby((df.marks != df.marks.shift(1)).cumsum())
.filter(lambda x: len(x) > 2)["marks"]
.unique()
)
print(x)
打印:
[83]
编辑:(df.marks != df.marks.shift(1)).cumsum()
行将创建一系列整数来标记不同的连续组:
0 1
1 2
2 3
3 3
4 3
5 4
6 4
7 5
Name: marks, dtype: int64
我们根据这些组对 df
进行分组,仅过滤大小 > 2 的组并打印唯一标记。
您可以使用运行长度编码获取长度并提取相关marks
。下面的代码使用 pdrle
包进行 运行 长度编码。
import pdrle
rle = pdrle.encode(df.marks)
rle.vals.loc[rle.runs.eq(3)]
# marks
# 2 83
# Name: vals, dtype: int64
您可以使用 diff
+ ne
+ cumsum
来识别连续标记组。然后索引恰好连续出现3次的标记:
groups = df['marks'].diff().ne(0).cumsum()
out = df.loc[groups.isin(groups.value_counts().eq(3).pipe(lambda x: x[x].index)), 'marks'].unique()
输出:
[83]
遍历列表three-at-a-time,如果所有三项都相等,则保存其中一项。
>>> marks = [83, 79, 83, 83, 83, 79, 79, 83]
>>> for (a,b,c) in zip(marks,marks[1:],marks[2:]):
... if a==b==c: print(a)
...
83
>>>
[a for (a,b,c) in zip(marks,marks[1:],marks[2:]) if a==b==c]
我正在寻找一种有效的函数来找到至少连续出现三次且不间断的标记。
输入示例:
import pandas as pd
marks = [83, 79, 83, 83, 83, 79, 79, 83]
student_id = [101, 102, 103, 104, 105, 106, 107, 108]
d = {'student_id':student_id,'marks':marks}
df = pd.DataFrame (d)
期望的输出:
83
如果可能的话,我正在寻找比使用 for
循环跟踪前 2 个标记的逐行循环更有效的方法。也就是说,我正在寻找比以下更好的东西:
def thrice_f (marks, number_of_apperances):
cache = marks[0]
counter = 1
for mark in marks[1:]:
if mark == cache:
counter += 1
if counter == number_of_apperances:
return cache
else:
counter = 1
cache = mark
是的,您可以使用 itertools.groupby()
:
from itertools import groupby
result = [key for key, group in groupby(marks) if len(list(group)) >= 3]
print(result)
这将给出连续出现超过 3 次的所有元素的列表:
[83]
如果你知道只有一个这样的组存在,你可以使用列表解包来提取单个元素:
[result] = [key for key, group in groupby(marks) if len(list(group)) >= n]
这输出:
83
另一个解决方案,仅使用 pandas
:
x = (
df.groupby((df.marks != df.marks.shift(1)).cumsum())
.filter(lambda x: len(x) > 2)["marks"]
.unique()
)
print(x)
打印:
[83]
编辑:(df.marks != df.marks.shift(1)).cumsum()
行将创建一系列整数来标记不同的连续组:
0 1
1 2
2 3
3 3
4 3
5 4
6 4
7 5
Name: marks, dtype: int64
我们根据这些组对 df
进行分组,仅过滤大小 > 2 的组并打印唯一标记。
您可以使用运行长度编码获取长度并提取相关marks
。下面的代码使用 pdrle
包进行 运行 长度编码。
import pdrle
rle = pdrle.encode(df.marks)
rle.vals.loc[rle.runs.eq(3)]
# marks
# 2 83
# Name: vals, dtype: int64
您可以使用 diff
+ ne
+ cumsum
来识别连续标记组。然后索引恰好连续出现3次的标记:
groups = df['marks'].diff().ne(0).cumsum()
out = df.loc[groups.isin(groups.value_counts().eq(3).pipe(lambda x: x[x].index)), 'marks'].unique()
输出:
[83]
遍历列表three-at-a-time,如果所有三项都相等,则保存其中一项。
>>> marks = [83, 79, 83, 83, 83, 79, 79, 83]
>>> for (a,b,c) in zip(marks,marks[1:],marks[2:]):
... if a==b==c: print(a)
...
83
>>>
[a for (a,b,c) in zip(marks,marks[1:],marks[2:]) if a==b==c]