Обновление: исправлено с более быстрым ответом
Для коротких фреймов данных или если ответ находится в начале фрейма данных, вы можете получить быстрые результаты с помощью цикла Python for
, который повторяется всначала совпадение, а затем разрывы (см. функцию for_loop()
ниже).Но если вам нужно отсканировать сотни или тысячи строк, чтобы найти соответствие, то, вероятно, быстрее использовать векторизованные функции, даже если они выполняют одну или две оценки по всей длине кадра данных.
Другие предлагали некоторые хорошие векторизованные операции, но добавленная ниже функция nonzero()
выглядит пока самой быстрой.
Некоторые функции, которые будут выполнять эту работу:
def nonzero():
# one-liner if you know there are matches:
# df.iloc[:(df.A >= 6).nonzero()[0][0],:]
indexes = (df.A.values >= 6).nonzero()[0]
if len(indexes) > 0:
return df.iloc[:indexes[0],:]
else:
return df
def for_loop():
result = df
for i, a in enumerate(df['A']):
if a >= 6:
result = df.iloc[:i,:]
break
return result
def idxmax():
return df.loc[:df.A.ge(4.50).idxmax()]
def cumprod():
return df[df.A.lt(6).cumprod().astype(bool)]
def next_idx():
return df.iloc[:next(idx for idx in df.index if df.iloc[idx, 0] > 6)]
def test_it(func, reps):
dur = timeit.timeit(stmt=func+'()', setup='from __main__ import df, '+func, number=reps)
print('{}: {}'.format(func, dur))
Тесты с небольшим фреймом данных:
df = pd.DataFrame.from_records([
[0.00, 514.51],
[0.75, 514.51],
[1.10, 514.42],
[3.52, 514.41],
[5.59, 514.43],
[6.52, 514.43],
[7.45, 514.42],
[5.53, 514.42],
[4.53, 514.36],
[3.61, 514.38],
[1.55, 514.36]
], columns = ['A','B'])
for func in ['nonzero', 'for_loop', 'idxmax', 'cumprod', 'next_idx']:
test_it(func, 10000)
# nonzero: 1.28068804741
# for_loop: 1.22211813927
# idxmax: 3.8852930069
# cumprod: 6.28086519241
# next_idx: 1.78734588623
Вот тест с большим фреймом данных, где первое совпадение - строка 600 000 из 1 000 000.Я пропустил for_loop
и next_idx
, потому что они занимают больше минуты для этого теста.
df = pd.DataFrame({'A':pd.np.arange(0,10,0.000001), 'B':514.51})
for func in ['nonzero', 'idxmax', 'cumprod']:
test_it(func, 100)
# nonzero: 3.25263190269
# idxmax: 9.08449816704
# cumprod: 24.7965559959
Так что похоже, что цикл Python for
с возможностью короткого замыкания может быть самым быстрым для небольших кадров данных, но для больших кадров данных быстрее протестировать каждую строку с помощью векторизованной операции, а затем найти смещение совпадающих строк (например, с помощью функции nonzero()
).