#python #pandas #dataframe #numpy
Вопрос:
У меня есть фрейм данных временных рядов, который содержит эволюцию цены с течением времени, и я использую столбец, называемый high_low
для хранения списка последних высоких/низких цен, которые были обнаружены.
В этой колонке можно указать до 10 последних высоких/низких цен high_low
.
Я хотел бы сгенерировать 3 новых столбца past_hl_3
past_hl2
, past_hl1
которые будут содержать значения 3 самых последних high_low
цен (то есть 3 самых верхних правых элемента строки).
Исходные данные :
date price high_low
0 2021-04-01 10 NaN
1 2021-04-02 12 NaN
2 2021-04-03 14 NaN
3 2021-04-04 13 "14"
4 2021-04-05 9 "14"
5 2021-04-06 16 "14 9"
6 2021-04-07 15 "14 9 16"
7 2021-04-08 14 "14 9 16"
8 2021-04-09 13 "14 9 16"
9 2021-04-10 12 "14 9 16"
10 2021-04-11 18 "14 9 16 12"
11 2021-04-12 19 "14 9 16 12"
12 2021-04-13 22 "14 9 16 12"
13 2021-04-14 25 "14 9 16 12"
Ожидаемые данные :
date price high_low price_hl_3 price_hl2 price_hl1
0 2021-04-01 10 NaN NaN NaN NaN
1 2021-04-02 12 NaN NaN NaN NaN
2 2021-04-03 14 NaN NaN NaN NaN
3 2021-04-04 13 "14" NaN NaN 14
4 2021-04-05 9 "14" NaN NaN 14
5 2021-04-06 16 "14 9" NaN 14 9
6 2021-04-07 15 "14 9 16" 14 9 16
7 2021-04-08 14 "14 9 16" 14 9 16
8 2021-04-09 13 "14 9 16" 14 9 16
9 2021-04-10 12 "14 9 16" 14 9 16
10 2021-04-11 18 "14 9 16 12" 9 16 12
11 2021-04-12 19 "14 9 16 12" 9 16 12
12 2021-04-13 22 "14 9 16 12" 9 16 12
13 2021-04-14 25 "14 9 16 12" 9 16 12
Я думал использовать что-то подобное, но это не работает, плюс мне все равно нужно будет преобразовать значения обратно в целые числа:
df['price_hl_3'] = np.where(len(df.high_low.str.split()) >= 3, df.high_low.str.split()[-3], np.nan)
df['price_hl_2'] = np.where(len(df.high_low.str.split()) >= 2, df.high_low.str.split()[-2], np.nan)
df['price_hl_1'] = np.where(len(df.high_low.str.split()) >= 1, df.high_low.str.split()[-1], np.nan)
Я уверен, что есть простой способ достичь ожидаемого результата, но я, кажется, не могу его найти.
Ответ №1:
Определите следующую функцию, чтобы получить содержимое 3 новых столбцов из поля high_low в текущей строке, разбитого на список:
def getElems(lst):
rv = lst[-3:][::-1] if isinstance(lst, list) else []
rv = [np.nan] * (3 - len(rv))
return pd.Series(rv[::-1], index=['price_hl3', 'price_hl2', 'price_hl1'])
Тогда беги:
result = df.join(df.high_low.str.split().apply(getElems))
В результате получается:
date price high_low price_hl3 price_hl2 price_hl1
0 2021-04-01 10 NaN NaN NaN NaN
1 2021-04-02 12 NaN NaN NaN NaN
2 2021-04-03 14 NaN NaN NaN NaN
3 2021-04-04 13 14 NaN NaN 14
4 2021-04-05 9 14 NaN NaN 14
5 2021-04-06 16 14 9 NaN 14 9
6 2021-04-07 15 14 9 16 14 9 16
7 2021-04-08 14 14 9 16 14 9 16
8 2021-04-09 13 14 9 16 14 9 16
9 2021-04-10 12 14 9 16 14 9 16
10 2021-04-11 18 14 9 16 12 9 16 12
11 2021-04-12 19 14 9 16 12 9 16 12
12 2021-04-13 22 14 9 16 12 9 16 12
13 2021-04-14 25 14 9 16 12 9 16 12
Обратите внимание, что тип всех 3 новых столбцов-object и non-NaN
элементы-это строки.
Первоначально я думал о преобразовании их в int, но у Pandas такие неудобные характеристики, что если столбец содержит как элементы int, так и NaN (что является «особым случаем» float), то весь столбец принуждается к плаванию.
Альтернатива для получения значений int
Последние версии Pandas включают метод convert_dtypes (), позволяющий изменять тип каждого столбца на наилучшие возможные типы dtypes с помощью поддержки dtypes pd.NA.
Так что ты можешь бежать:
result = df.join(df.high_low.str.split().apply(getElems)).convert_dtypes()
а затем все 3 новых столбца (и, кроме того, цена) преобразуются в
Int64 (обратите внимание на заглавную букву «I» в названии типа).
Распечатайте результат, чтобы увидеть разницу.
На этот раз вместо NaN новые столбцы содержат <NA><NA> (другое представление «отсутствующего» значения), а другие значения являются просто целыми числами.
Ответ №2:
Давайте split
тогда попробуем sorted
df['high_low'] = df['high_low'].str.strip('"')
df = df.join(df['high_low'].str.split(' ',expand=True).
apply(lambda x : pd.Series(sorted(x,key=pd.notnull)),1)).iloc[:,1:]
df
Out[157]:
price high_low 0 1 2 3
0 10 NaN NaN NaN NaN NaN
1 12 NaN NaN NaN NaN NaN
2 14 NaN NaN NaN NaN NaN
3 13 14 None None None 14
4 9 14 None None None 14
5 16 14 9 None None 14 9
6 15 14 9 16 None 14 9 16
7 14 14 9 16 None 14 9 16
8 13 14 9 16 None 14 9 16
9 12 14 9 16 None 14 9 16
10 18 14 9 16 12 14 9 16 12
11 19 14 9 16 12 14 9 16 12
12 22 14 9 16 12 14 9 16 12
13 25 14 9 16 12 14 9 16 12