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

Программы на Python
Anonymous
 Вычисление перекрестных рейтингов с использованием аккуратного полярного фрейма данных

Сообщение Anonymous »

Мне нужно вычислить перекрестные рейтинги ряда торговых ценных бумаг. Рассмотрим следующий pl.DataFrame в длинном (аккуратном) формате. Он состоит из трех разных символов с соответствующими ценами, причем каждый символ также имеет специальный (т. е. локальный) торговый календарь.

Код: Выделить всё

import polars as pl

df = pl.DataFrame(
{
"symbol": [*["symbol1"] * 6, *["symbol2"] * 5, *["symbol3"] * 5],
"date": [
"2023-12-30", "2023-12-31", "2024-01-03", "2024-01-04", "2024-01-05", "2024-01-06",
"2023-12-30", "2024-01-03", "2024-01-04", "2024-01-05", "2024-01-06",
"2023-12-30", "2023-12-31", "2024-01-03", "2024-01-04", "2024-01-05",
],
"price": [
100, 105, 110, 115, 120, 125,
200, 210, 220, 230, 240,
3000, 3100, 3200, 3300, 3400,
],
}
)

print(df)

Код: Выделить всё

shape: (16, 3)
┌─────────┬────────────┬───────┐
│ symbol  ┆ date       ┆ price │
│ ---     ┆ ---        ┆ ---   │
│ str     ┆ str        ┆ i64   │
╞═════════╪════════════╪═══════╡
│ symbol1 ┆ 2023-12-30 ┆ 100   │
│ symbol1 ┆ 2023-12-31 ┆ 105   │
│ symbol1 ┆ 2024-01-03 ┆ 110   │
│ symbol1 ┆ 2024-01-04 ┆ 115   │
│ symbol1 ┆ 2024-01-05 ┆ 120   │
│ …       ┆ …          ┆ …     │
│ symbol3 ┆ 2023-12-30 ┆ 3000  │
│ symbol3 ┆ 2023-12-31 ┆ 3100  │
│ symbol3 ┆ 2024-01-03 ┆ 3200  │
│ symbol3 ┆ 2024-01-04 ┆ 3300  │
│ symbol3 ┆ 2024-01-05 ┆ 3400  │
└─────────┴────────────┴───────┘
Первый шаг — вычислить периодическую доходность с помощью pct_change, а затем использовать Pivot для выравнивания символов по дате.

Код: Выделить всё

returns = df.drop_nulls().with_columns(
pl.col("price").pct_change(n=2).over("symbol").alias("return")
).pivot(on="symbol", index="date", values="return")

print(returns)

Код: Выделить всё

shape: (6, 4)
┌────────────┬──────────┬──────────┬──────────┐
│ date       ┆ symbol1  ┆ symbol2  ┆ symbol3  │
│ ---        ┆ ---      ┆ ---      ┆ ---      │
│ str        ┆ f64      ┆ f64      ┆ f64      │
╞════════════╪══════════╪══════════╪══════════╡
│ 2023-12-30 ┆ null     ┆ null     ┆ null     │
│ 2023-12-31 ┆ null     ┆ null     ┆ null     │
│ 2024-01-03 ┆ 0.1      ┆ null     ┆ 0.066667 │
│ 2024-01-04 ┆ 0.095238 ┆ 0.1      ┆ 0.064516 │
│ 2024-01-05 ┆ 0.090909 ┆ 0.095238 ┆ 0.0625   │
│ 2024-01-06 ┆ 0.086957 ┆ 0.090909 ┆ null     │
└────────────┴──────────┴──────────┴──────────┘
Следующим шагом является использование concat_list для создания списка для вычисления рангов для каждой строки (по убыванию, т. е. наивысший результат получает ранг 1).

Код: Выделить всё

ranks = (
returns.with_columns(all_symbols=pl.concat_list(pl.all().exclude("date")))
.select(
pl.all().exclude("all_symbols"),
pl.col("all_symbols")
.list.eval(
pl.element().rank(descending=True, method="ordinal").cast(pl.UInt8)
)
.alias("rank"),
)
)

print(ranks)

Код: Выделить всё

shape: (6, 5)
┌────────────┬──────────┬──────────┬──────────┬────────────────────┐
│ date       ┆ symbol1  ┆ symbol2  ┆ symbol3  ┆ rank               │
│ ---        ┆ ---      ┆ ---      ┆ ---      ┆ ---                │
│ str        ┆ f64      ┆ f64      ┆ f64      ┆ list[u8]           │
╞════════════╪══════════╪══════════╪══════════╪════════════════════╡
│ 2023-12-30 ┆ null     ┆ null     ┆ null     ┆ [null, null, null] │
│ 2023-12-31 ┆ null     ┆ null     ┆ null     ┆ [null, null, null] │
│ 2024-01-03 ┆ 0.1      ┆ null     ┆ 0.066667 ┆ [1, null, 2]       │
│ 2024-01-04 ┆ 0.095238 ┆ 0.1      ┆ 0.064516 ┆ [2, 1, 3]          │
│ 2024-01-05 ┆ 0.090909 ┆ 0.095238 ┆ 0.0625   ┆ [2, 1, 3]          │
│ 2024-01-06 ┆ 0.086957 ┆ 0.090909 ┆ null     ┆ [2, 1, null]       │
└────────────┴──────────┴──────────┴──────────┴────────────────────┘
Теперь мы, наконец, подошли к самому вопросу:

Я хотел бы снова развернуть ранги и создать аккуратный фрейм данных. Я ищу следующие столбцы: символ, дата, возврат и ранг. Я подумывал о создании трех новых столбцов (в основном с помощью разнесения для распаковки списка, но при этом будут создаваться только новые строки, а не столбцы).
Кроме того, мне интересно, нужно ли мне сначала поворачивать df или есть лучший способ напрямую работать с исходным df в аккуратном формате? На самом деле мне нужна производительность, поскольку df может иметь миллионы строк.

Подробнее здесь: https://stackoverflow.com/questions/789 ... -dataframe

Вернуться в «Python»