提问人:jaried 提问时间:12/10/2021 最后编辑:jaried 更新时间:12/14/2021 访问量:189
如何更快地找到从第一个位置开始的组的最后一个真实位置为真?
How to find the last true position of the group starting from the first position to be true faster?
问:
我有一个 dataframe,演示由 生成。generate_data()
- 如果数据列中的第一个值为 false,则返回 0。
- 如果数据列的第一个值为 true,则返回连续 true 的最后一个位置的顺序。
我写了两种方法:和sort_data()
sort_data2()
%timeit sort_order(df.copy())
1.12 ms ± 14.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit sort_order2(df.copy())
715 µs ± 10.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
有没有更快的方法?
我的代码如下:
import pandas as pd
import numpy as np
def generate_data():
order = range(1,7)
data = [True, True, False, False, True, False]
c = {'order': order,
'data': data}
df = pd.DataFrame(c)
return df
def sort_order(df):
order_first_false = df.loc[~df.data, 'order']
if len(order_first_false) == 0:
order_last_true = df.order.values[-1]
else:
order_first_false = order_first_false.values[0]
df = df[df.order < order_first_false]
if len(df):
order_last_true = df.order.values[-1]
else:
order_last_true = 0
return order_last_true
def sort_order2(df):
groups = df[f'data'].ne(True).cumsum()
len_true = len(groups[groups == 0])
if len_true:
order_last_true = df.at[df.index[len_true - 1], 'order'].max()
else:
order_last_true = 0
return order_last_true
def main():
df = generate_data()
print(df)
order_last_true = sort_order(df.copy())
print(order_last_true)
order_last_true = sort_order2(df.copy())
print(order_last_true)
if __name__ == '__main__':
main()
我尊重的结果是:
order data
0 1 True
1 2 True
2 3 False
3 4 False
4 5 True
5 6 False
2
2
答:
4赞
jezrael
12/10/2021
#1
使用 numba 处理第一个 s 块的值,灵感来自此解决方案:True
from numba import njit
@njit
def sort_order3(a, b):
if not a[0]:
return 0
else:
for i in range(1, len(a)):
if not a[i]:
return b[i - 1]
return b[-1]
df = generate_data()
print (sort_order3(df['data'].to_numpy(), df['order'].to_numpy()))
评论
0赞
jaried
12/11/2021
谢谢你的回答。你的回答对我来说非常有价值。%timeit sort_order3(df.copy()['data'].to_numpy(), df.copy()['order'].to_numpy()) 300 μs ± 2.23 μs (平均±标准开发 7 次,每次 1000 次循环)
1赞
Andre
12/10/2021
#2
也许我遗漏了一些东西,但你为什么不直接获取第一个索引,然后使用该索引来获取列中的值?False
df.data
df.order
例如:
def sort_order3(df):
try:
idx = df.data.to_list().index(False)
except ValueError: # meaning there is no False in df.data
idx = df.data.size - 1
return df.order[idx]
或者对于非常大的数据,numpy 可能会更快:
def sort_order4(df):
try:
idx = np.argwhere(~df.data.values)[0, 0]
except IndexError: # meaning there is no False in df.data
idx = df.data.size - 1
return df.order[idx]
我设备上的计时:
%timeit sort_order(df.copy())
565 µs ± 6.29 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit sort_order2(df.copy())
443 µs ± 10.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit sort_order3(df.copy())
96.5 µs ± 2.16 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit sort_order4(df.copy())
112 µs ± 5.06 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
评论
0赞
jaried
12/11/2021
谢谢。%timeit sort_order3(df.copy()) 226 μs ± 3.08 μs (±平均 7 次运行,每次 1000 次循环)%timeit sort_order4(df.copy()) 250 μs ± 2.14 μs (平均±标准开发 7 次运行,每次 1000 次循环)
0赞
jaried
12/14/2021
当第一个值为 false 时,会出现问题。
0赞
Andre
12/14/2021
问题是什么?
0赞
jaried
12/14/2021
如果 change data = [False, True, False, False, True, False], sort_order3 并且sort_order4得到 1,则期望值为 0。
0赞
Andre
12/14/2021
该函数从列中第一个索引处的列中返回值。因此,如果索引为 0,则函数会重新运行,即 1 ()。df.order
False
df.data
df.order[0]
as df.order == range(1,7)
评论