Как эффективно создать индексный DataFrame Polars из нескольких разреженных серий?Python

Программы на Python
Anonymous
Как эффективно создать индексный DataFrame Polars из нескольких разреженных серий?

Сообщение Anonymous »

Я хотел бы создать DataFrame, который имеет «индекс» (целое число) из ряда (разреженных) серий, где индекс (или первичный ключ) НЕ обязательно представляет собой последовательные целые числа. Каждая серия похожа на вектор кортежа (индекс, значение) или сопоставления {index: value.
(1) Небольшой пример
В Pandas это очень просто, поскольку мы можем создать DataFrame за раз, например
>>> pd.DataFrame({
"A": {0: 'a', 20: 'b', 40: 'c'},
"B": {10: 'd', 20: 'e', 30: 'f'},
"C": {20: 'g', 30: 'h'},
}).sort_index()

A B C
0 a NaN NaN
10 NaN d NaN
20 b e g
30 NaN f h
40 c NaN NaN

но я не могу найти простой способ добиться аналогичного результата с помощью Polars. Как описано в разделе «Исходники из Pandas», Polars не использует индекс, в отличие от Pandas, и каждая строка индексируется по ее целочисленной позиции в таблице; поэтому мне может потребоваться представить «индексированную» серию с помощью DataFrame с двумя столбцами:
A = pl.DataFrame({ "index": [0, 20, 40], "A": ['a', 'b', 'c'] })
B = pl.DataFrame({ "index": [10, 20, 30], "B": ['d', 'e', 'f'] })
C = pl.DataFrame({ "index": [20, 30], "C": ['g', 'h'] })

Я пытался объединить эти несколько DataFrames, объединив их в столбце индекса:
>>> A.join(B, on='index', how='full', coalesce=True).join(C, on='index', how='full', coalesce=True).sort(by='index')

shape: (5, 4)
┌───────┬──────┬──────┬──────┐
│ index ┆ A ┆ B ┆ C │
│ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ str ┆ str ┆ str │
╞═══════╪══════╪══════╪══════╡
│ 0 ┆ a ┆ null ┆ null │
│ 10 ┆ null ┆ d ┆ null │
│ 20 ┆ b ┆ e ┆ g │
│ 30 ┆ null ┆ f ┆ h │
│ 40 ┆ c ┆ null ┆ null │
└───────┴──────┴──────┴──────┘

Это дает желаемый результат, но мне интересно:
  • (i) есть ли более краткий способ сделать это для многих столбцов и
  • (ii) как сделать эту операцию максимально эффективной.
Альтернативы?
Я также пробовал внешние соединения, поскольку это один из способов объединить фреймы данных с разным количеством столбцов и строк, как описано выше.
Другое альтернативы, которые я пробовал, включают диагональную конкатенацию, но она не дедуплицирует и не объединяет индекс:
>>> pl.concat([A, B, C], how='diagonal')

index A B C
0 0 a None None
1 20 b None None
2 40 c None None
3 10 None d None
4 20 None e None
5 30 None f None
6 20 None None g
7 30 None None h

(2) Эффективное построение большой таблицы
Подход, который я нашел выше, дает желаемые результаты, которые мне хотелось бы, но я чувствую, что должен быть лучший путь с точки зрения производительности. Рассмотрим случай с более большими таблицами; скажем, 300 000 строк и 20 столбцов:
N, C = 300000, 20
pls = []
pds = []

for i in range(C):
A = pl.DataFrame({
"index": np.linspace(i, N*3-i, num=N, dtype=np.int32),
f"A{i}": np.arange(N, dtype=np.float32),
})
pls.append(A)

B = A.to_pandas().set_index("index")
pds.append(B)

Способ объединения двух столбцов подряд работает несколько медленнее, чем я ожидал:
%%time
F = functools.reduce(lambda a, b: a.join(b, on='index', how='full', coalesce=True), pls)
F.sort(by='index')

CPU times: user 1.49 s, sys: 97.8 ms, total: 1.59 s
Wall time: 611 ms

или однопроходное создание в pd.DataFrame:
%%time
pd.DataFrame({
f"A{i}": pds[f'A{i}'] for i in range(C)
}).sort_index()

CPU times: user 230 ms, sys: 50.7 ms, total: 281 ms
Wall time: 281 ms


Подробнее здесь: https://stackoverflow.com/questions/744 ... -sparse-se

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