У меня есть фрейм данных с 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
в новый фрейм данных на основе нескольких условий:
Если все это удовлетворено, я хочу написать новый фрейм данных:
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
?
Мне кажется, это выглядит немного сложнее, чем есть на самом деле. На самом деле я просто пытаюсь сравнить значения X, Y, Z (вместе в виде одной строки из 3 столбцов) или просто значения X (в виде одной строки из 1 столбца) и наложить на них условия. Есть ли что-нибудь полезное, что я могу предоставить, чтобы помочь лучше понять?
Я понимаю, что вы делаете, но попробуйте сделать шаг назад и подумать о решении проблемы по-другому. Но, может быть, я ошибаюсь
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)
?
Я немного изменил ваши образцы данных, чтобы получить один положительный результат:
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)
Обратите внимание, что тип = целое будет соблюдаться только для столбцов Икс и у, потому что значения в столбце г имеют дробную часть.
Не уверен, чего вы пытаетесь достичь, но это выглядит довольно сложно и подвержено ошибкам. Разве нет другого способа добиться того, что вы пытаетесь сделать?