#python #pandas #dataframe #compare
#python #pandas #фрейм данных #Сравнить
Вопрос:
Как я могу сравнить значение «Цены» каждой строки со следующими 2 строками? Я хочу запустить функцию для каждой строки: если текущая цена ниже в любой из следующих 2 часов, я хочу присвоить «Low» столбцу «Действие» текущей строки. Если текущая цена выше, чем за следующие 2 часа, тогда назначьте «Высокую«. Если текущая цена не является ни самой высокой, ни самой низкой за все сравниваемые 3 часа, назначьте «Hold».
Итак, как я могу взять цену из каждой строки и сравнить ее со следующими 2 строками с Pandas? Фрейм данных выглядит следующим образом:
data.head()
Date Time Price Month Hour Action
0 2018-01-01 0 2633 January 1 NaN
1 2018-01-01 1 2643 January 2 NaN
2 2018-01-01 2 2610 January 3 NaN
3 2018-01-01 3 2470 January 4 NaN
4 2018-01-01 4 2474 January 5 NaN
Желаемый результат в этом случае будет выглядеть следующим образом:
data.head()
Date Time Price Month Hour Action
0 2018-01-01 0 2633 January 1 Hold
1 2018-01-01 1 2643 January 2 High
2 2018-01-01 2 2610 January 3 High
3 2018-01-01 3 2470 January 4 Low
4 2018-01-01 4 2474 January 5 Hold
Спасибо.
редактировать: вероятно, это можно легко сделать с помощью циклов for, но я уверен, что у pandas есть какой-то лучший способ сделать это
Комментарии:
1. Кто когда-либо отклонял этот вопрос, должен хотя бы прокомментировать причину.
2. Какова логика, стоящая за
Low
иHold
в строках 3 и 4? Поскольку нет двух строк для сравнения? Как последняя строка узнает своюHold
?3. На самом деле фрейм данных намного длиннее 5 строк, я просто сравнил эти последние строки с тем, что осталось в примере .head() (поэтому «Удерживайте», потому что нет более высоких или более низких значений). Но в любом случае этот алгоритм является упрощением, реальный вопрос заключается в том, как можно сравнить каждую строку со следующими строками, а затем присвоить некоторые значения.
4. Итак, я опубликую ответ, который не будет учитывать только последние две строки вашего фрейма данных. Поскольку ей не с чем сравнивать. Достаточно ли этого для вас?
5. Я думаю, это было бы здорово!
Ответ №1:
Вы можете использовать функцию data['Price'].shift(-1)
для получения следующей цены в текущей строке и data['Price'].shift(-2)
для получения цены на 2 периода вперед в текущей строке. Далее вы можете использовать срез, чтобы выбрать строки, в которых следующие две строки выше или ниже текущей цены, и заполнить их желаемым значением.
Смотрите ниже, как это делается:
# Check if the current price is lower than the next 2 rows and assign to the column 'Action' the value 'Low' if this is true
data.loc[(data['Price'].shift(-2)> data['Price']) amp; (data['Price'].shift(-1) > data['Price']), 'Action'] = 'Low'
# Check if the current price is higher than the next 2 rows and assign to the column 'Action' the value 'High' if this is true
data.loc[(data['Price'].shift(-2)< data['Price']) amp; (data['Price'].shift(-1) < data['Price']), 'Action'] = 'High'
# fill the rest of the rows with the value Hold
data['Action'] = data['Action'].fillna('Hold')
Комментарии:
1. Что это вернет для последних двух строк? Вы это проверили? Я думаю, что это вернет
Hold
, что неверно.2. Он вернет
Hold
то, что вы указали. В вопросе было указано, чтоIf the current price is nor the highest or the lowest of all the 3 hours compared, assign "Hold"
. Поскольку значений нет, это будетHold
. Это будет перезаписано, когда следующая строка будет добавлена в фрейм данных.
Ответ №2:
Мы можем написать некоторые условия для этого. И выбрать значения на основе этих условий с помощью np.select
. В наших условиях мы используем .shift
для этого который сравнивает текущую строку со следующими двумя строками.
Обратите внимание, что вернутся две последние строки Unknown
, поскольку у нас нет данных за два дня для сравнения. Что имеет смысл.
# Print the extended dataframe which is used
print(df)
Date Time Price Month Hour Action
0 2018-01-01 0 2633 January 1 NaN
1 2018-01-01 1 2643 January 2 NaN
2 2018-01-01 2 2610 January 3 NaN
3 2018-01-01 3 2470 January 4 NaN
4 2018-01-01 4 2474 January 5 NaN
5 2018-01-01 5 2475 January 6 NaN
6 2018-01-01 6 2471 January 7 NaN
Определите условия, варианты и примените np.select
conditions = [
(df['Price'] > df['Price'].shift(-1)) amp; (df['Price'] > df['Price'].shift(-2)),
((df['Price'].between(df['Price'].shift(-1), df['Price'].shift(-2))) | (df['Price'].between(df['Price'].shift(-2), df['Price'].shift(-1)))),
(df['Price'] < df['Price'].shift(-1)) amp; (df['Price'] < df['Price'].shift(-2)),
]
choices = ['High', 'Hold', 'Low']
df['Action'] = np.select(conditions, choices, default='Unknown')
print(df)
Date Time Price Month Hour Action
0 2018-01-01 0 2633 January 1 Hold
1 2018-01-01 1 2643 January 2 High
2 2018-01-01 2 2610 January 3 High
3 2018-01-01 3 2470 January 4 Low
4 2018-01-01 4 2474 January 5 Hold
5 2018-01-01 5 2475 January 6 Unknown
6 2018-01-01 6 2471 January 7 Unknown
Комментарии:
1. Спасибо, я не знал о .shift (), это именно то, что мне было нужно. Я пытаюсь ради интереса посмотреть, можно ли использовать pandas для некоторой оптимизации ценового арбитража, затем я уточню алгоритм, условия и т.д. Еще раз спасибо!
2. Конечно, нет проблем, рад, что смог помочь. Если вам нужна дополнительная помощь, просто спросите 🙂
Ответ №3:
Я начал с создания исходного фрейма данных, немного длиннее вашей головы:
df = pd.DataFrame(data=[[ '2018-01-01', 0, 2633, 'January', 1 ],
[ '2018-01-01', 1, 2643, 'January', 2 ], [ '2018-01-01', 2, 2610, 'January', 3 ],
[ '2018-01-01', 3, 2470, 'January', 4 ], [ '2018-01-01', 4, 2474, 'January', 5 ],
[ '2018-01-01', 5, 2475, 'January', 6 ]],
columns=['Date', 'Time', 'Price', 'Month', 'Hour']); df
Первым шагом является вычисление 2 вспомогательных столбцов P1
с ценой
начиная со следующего часа и P2
с ценой за 2 часа вперед:
df['P1'] = df.Price.diff(-1).fillna(0, downcast='infer')
df['P2'] = df.Price.diff(-2).fillna(0, downcast='infer')
Затем нам нужна функция, которая будет применена к каждой строке:
def fn(row):
if row.P1 < 0 and row.P2 < 0:
return 'Low'
elif row.P1 > 0 and row.P2 > 0:
return 'High'
else:
return 'Hold'
И последний шаг — вычислить новый столбец (применяя вышеуказанную функцию)
и удалить вспомогательные столбцы:
df['Action'] = df.apply(fn, axis=1)
df.drop(['P1', 'P2'], axis=1, inplace=True)