Как сравнить каждую строку фрейма данных со следующими 2 строками и изменить текущую строку на основе этих 3 строк и алгоритма? (Pandas)

#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)