Нарезка фрейма данных по нескольким условиям Python

У меня есть фрейм данных с 3 столбцами:

df:

x       y      z
334     290    3350.0
334     291    3350.5
334     292    3360.1
335     292    3360.1
335     292    3360.1
335     290    3351.0
335     290    3352.5
335     291    3333.1
335     291    3333.1
.
.

Я хотел бы проверить и проанализировать значения каждой строки от row = n до row = n+7 в новый фрейм данных на основе нескольких условий:

  1. дф[п] != дф[п+1]
  2. дф[п] != дф[п+3]
  3. дф[п] != дф[п+5]
  4. df['x'][n] < df['x'][n+2]
  5. df['x'][n] > df['x'][n+3]

Если все это удовлетворено, я хочу написать новый фрейм данных:

df_new = pd.concat([df[n], df[n+1], df[n+2], df[n+3], 
df[n+4], df[n+5], df[n+6], df[n+7]])

Таким образом, алгоритм + вывод будет выглядеть так:

for df[n] = 0:
1) [334     290    3350.0] != [334     291    3350.5]  True
2) [334     290    3350.0] != [335     292    3360.1]  True
3) [334     290    3350.0] != [335     290    3351.0]  True
4) 335 < 334  False
5) 335 > 335  False

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

df_new(first iteration) = df_new.concat([....]) = empty row values

Есть ли простой способ сделать это со скоростью в Pandas?

Не уверен, чего вы пытаетесь достичь, но это выглядит довольно сложно и подвержено ошибкам. Разве нет другого способа добиться того, что вы пытаетесь сделать?

Erfan 27.05.2019 20:59

Мне кажется, это выглядит немного сложнее, чем есть на самом деле. На самом деле я просто пытаюсь сравнить значения X, Y, Z (вместе в виде одной строки из 3 столбцов) или просто значения X (в виде одной строки из 1 столбца) и наложить на них условия. Есть ли что-нибудь полезное, что я могу предоставить, чтобы помочь лучше понять?

HelloToEarth 27.05.2019 21:04

Я понимаю, что вы делаете, но попробуйте сделать шаг назад и подумать о решении проблемы по-другому. Но, может быть, я ошибаюсь

Erfan 27.05.2019 21:14
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
3
691
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

A. Получите соответствующие смены:

    n1 = df.shift(-1)
    n2 = df.shift(-2)
    n3 = df.shift(-3)
    n5 = df.shift(-5)

Б. Удовлетворить условиям 1, 2 и 3:

cond = (df != n1) & (df != n3) & (df != n5)

C. Удовлетворить условиям 4, 5:

 cond['holder'] = (df.x < n2.x) & (df.x < n3.x)

D. Получить серию логических значений (нам нужна любая строка со всеми значениями «True»):

boolidx = cond.all(axis=1)

E. Используйте для получения результата:

df.loc[boolidx]
cond.any(axis=1) или cond.all(axis=1)?
Quang Hoang 27.05.2019 21:50

Я немного изменил ваши образцы данных, чтобы получить один положительный результат:

df = pd.DataFrame(data=[
    [ 334, 290, 3350.0 ],
    [ 334, 291, 3350.5 ],
    [ 334, 292, 3360.1 ],
    [ 335, 292, 3360.1 ],
    [ 335, 292, 3360.1 ],
    [ 333, 290, 3351.0 ],
    [ 335, 290, 3352.5 ],
    [ 335, 291, 3333.1 ],
    [ 335, 291, 3333.1 ]], columns=['x', 'y', 'z'])

Затем, по соображениям эффективности, я определил следующую функцию:

def roll_win(a, win):
    shape = (a.shape[0] - win + 1, win, a.shape[1])
    strides = (a.strides[0],) + a.strides
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

Он создает таблицу 3D, где измерения 2-й и 3-й являются "скользящими". windows" из исходного массива Нампиа. Размер окна победить, скольжение по вертикали. Таким образом, обработка последовательных окон требует выполнения цикла первая ось сгенерированной таблицы (см. ниже).

Благодаря использованию функции as_stried он работает значительно быстрее, чем любой «обычный» цикл Python (сравните время выполнения с другими решениями).

Я не мог использовать скользящие окна, предоставленный Панды, потому что они создан для вычисления некоторой статистики, а не для вызова какой-либо пользовательской функции на все содержимое текущего окна.

Затем я вызываю эту функцию:

tbl = roll_win(df.values, 7)

Обратите внимание, что массив Нампи должен иметь тип элемента Один, поэтому тип "обобщен" до плавать, потому что один исходный столбец Тип плавать.

Затем у нас есть этапы подготовки к циклу, обрабатывающему каждое скользящее окно:

res = []    # Result container
idx = 0     # Rolling window index

Остальная часть программы представляет собой цикл:

while idx < len(tbl):
    tt = tbl[idx]  # Get the current rolling window (2-D)
    r0 = tt[0]     # Row 0
    # Condition
    cond = not((r0 == tt[1]).all() and (r0 == tt[3]).all()\
        and (r0 == tt[5]).all()) and tt[0][0] < tt[2][0]\
        and tt[0][0] > tt[3][0]
    if cond:   # OK
        # print(idx)
        # print(tt)
        res.extend(tt)  # Add to result
        idx += 7        # Skip the current result
    else:      # Failed
        idx += 1        # Next loop for the next window

В "положительном" случае решила начать следующую петлю с ряда следующий текущее совпадение (идентификатор += 7), чтобы избежать возможного частичного перекрывающиеся наборы исходных строк. Если вам не нужна эта функция, добавьте 1 do IDX в обоих случаях.

Для демонстрационных целей вы можете раскомментировать тестовые распечатки выше.

Осталось только создать целевой DataFrame из строк собрано в разрешение:

df2 = pd.DataFrame(data=res, columns=['x', 'y', 'z'], dtype=int)

Обратите внимание, что тип = целое будет соблюдаться только для столбцов Икс и у, потому что значения в столбце г имеют дробную часть.

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