Вывод ограничения скорости Pandas на основе минимального изменения в столбце

У меня есть фрейм данных, в котором есть столбец t, который представляет собой монотонно увеличивающееся целое число. Я хочу отфильтровать фрейм данных так, чтобы выбрать как можно больше строк, но в ВЫХОДЕ у меня никогда не было двух строк, где t - t.shift(1) <= 10 (и всегда включая первую строку входного кадра данных в выходной). Это отличается от df[df['t'].diff().fillna(20) >= 10], потому что у меня может быть строка входных строк, где t равно 5 друг от друга, и просто взятие разницы на входе приведет к выдаче из них всех.

В неэффективном псевдокоде это будет что-то вроде:

last_chosen = None
inds = []
for i, t in enumerate(df['t']):
    if last_chosen is None or t - last_chosen >= 10:
        last_chosen = t
        inds.append(df.index[i])

new_df = df[inds]

Есть ли какой-нибудь эффективный способ сделать это?

Обновлено: Минимальный пример:


def filt(df, gap=10):
    last_chosen = None
    inds = []
    for i, t in enumerate(df['t']):
        if last_chosen is None or t - last_chosen >= gap:
            last_chosen = t
            inds.append(df.index[i])

    return df.loc[inds]
    


d = pd.DataFrame(dict(
     t = [5, 7, 9, 10, 15, 20, 30, 45, 50, 55, 60, 70]))

(d['t'][d['t'].diff().fillna(10) >= 10])  # gives [5, 30, 45, 70]

filt(d)['t'] # gives [5, 15, 30, 45, 55, 70] which is desired

Можете ли вы предоставить минимальный воспроизводимый пример (вход + ожидаемый результат) для ясности?

mozway 13.06.2024 17:00

Пример поможет. Особенно тот, который показывает, что вы пробовали, какой результат это дало и чем это отличается от того, что вы хотите. Потому что я не понимаю, почему «строка входных строк, где расстояние между t равно 5», может быть выброшена при использовании diff.

steliosbl 13.06.2024 17:02

IIUC, вы не можете векторизовать эту операцию. Вы можете использовать numba, чтобы ускорить процесс.

mozway 13.06.2024 17:03

Похоже, @mozway прав — это похоже на stackoverflow.com/questions/55738163/…, насколько я могу судить, единственным решением был наивный цикл

user2721897 13.06.2024 17:21
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
4
75
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Как упоминалось ранее в комментариях, вы не можете векторизовать эту операцию. Поскольку наличие значения зависит от судьбы предыдущих значений, необходим итерационный процесс, т. е. цикл.

Таким образом, ваш код в порядке, однако вы можете значительно улучшить его скорость, используя numba. Вам нужно немного изменить код для numba, чтобы он принимал входные данные (в виде массива numpy):

from numba import jit

@jit
def numba_filt(a, gap=10):
    last_chosen = None
    inds = []
    for i, t in enumerate(a):
        if last_chosen is None or t - last_chosen >= gap:
            last_chosen = t
            inds.append(i)

    return inds

def filt(df, gap=10, col='t'):
    return df.iloc[numba_filt(df[col].to_numpy(), gap=gap)]

filt(d)['t']

Выход:

0      5
4     15
6     30
7     45
9     55
11    70
Name: t, dtype: int64
тайминги

Протестировав это на 2 млн строк, мы получили увеличение скорости примерно в 5 раз.

# python loop
303 ms ± 6.91 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

# numba
60.9 ms ± 682 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Используемый вход:

df = pd.DataFrame({'t': np.sort(np.random.choice(10_000_000, 2_000_000, replace=False))})
import numpy as np
import pandas as pd

df = pd.DataFrame({'t': [5, 7, 9, 10, 15, 20, 30, 45, 50, 55, 60, 70]})
print(df)
gap = 10
t_values = df['t'].values
chosen = np.zeros(len(t_values),dtype= bool)
chosen[0] = True
last_chosen_value= t_values[0]
while True :
    next_value = last_chosen_value + gap
    next_index = np.searchsorted(t_values,next_value, side ='left')
    if next_index >= len(t_values) :break
    chosen[next_index] =True
    last_chosen_value = t_values[next_index]
    print("last_chosen_value :",last_chosen_value)
 
res = df[chosen] 
print(res)  
'''
     t
0    5
4   15
6   30
7   45
9   55
11  70
'''  

Другие вопросы по теме

Похожие вопросы

Почему тип данных numpy возвращает void, когда он был создан как float64?
Получить (приблизительную) матрицу преобразования вращения (numpy) на единичной сфере с учетом отображения векторов (n = 12)
Невозможно удалить виджет после активации флажка в Python Tkinter
Как в Confluence воспроизвести ручной поиск с помощью поиска API?
Надежный способ проверить, был ли метод обернут декоратором изнутри
Как проверить, не может ли пользователь отправлять сообщения (был ограничен или отключен звук) в чате Telegram с помощью Telethon API?
Как сохранить векторы, созданные AzureOpenAIEmbeddingSkill, в индексаторе с учетом моей текущей настройки
Каков наиболее эффективный способ заполнения нескольких столбцов значениями из других столбцов таким образом, чтобы их можно было соединить с суффиксом?
Разбиение на страницы данных из DynamoDB при использовании FilterExpression и Limit
Get_swagger_ui_html вызывает отображение нежелательных параметров сервера в приложении FastAPI