У меня есть DataFrame со столбцом, содержащим списки строк. Я хочу отфильтровать DataFrame, чтобы удалить строки с повторяющимися значениями столбца списка.
Например,
import polars as pl
# Create a DataFrame with a list[str] type column
data = pl.DataFrame({
"id": [1, 2, 3, 4],
"values": [
["a", "a", "a"], # first two rows are duplicated
["a", "a", "a"],
["b", "b", "b"],
["c", "d", "e"]
]
})
print(data)
shape: (4, 2)
┌─────┬─────────────────┐
│ id ┆ values │
│ --- ┆ --- │
│ i64 ┆ list[str] │
╞═════╪═════════════════╡
│ 1 ┆ ["a", "a", "a"] │
│ 2 ┆ ["a", "a", "a"] │
│ 3 ┆ ["b", "b", "b"] │
│ 4 ┆ ["c", "d", "e"] │
└─────┴─────────────────┘
Желаемый результат:
shape: (3, 2)
┌─────┬─────────────────┐
│ id ┆ values │
│ --- ┆ --- │
│ i64 ┆ list[str] │
╞═════╪═════════════════╡
│ 1 ┆ ["a", "a", "a"] │
│ 3 ┆ ["b", "b", "b"] │
│ 4 ┆ ["c", "d", "e"] │
└─────┴─────────────────┘
Использование метода unique
не работает для типа list[str]
(однако он работает, когда список содержит числовые типы).
data.unique(subset = "values")
ComputeError: grouping on list type is only allowed if the inner type is numeric
Вы можете привести строки к категории:
(df.with_columns(pl.col("values").cast(pl.List(pl.Categorical)))
.unique(subset = "values", maintain_order=True))
shape: (3, 2)
┌─────┬─────────────────┐
│ id ┆ values │
│ --- ┆ --- │
│ i64 ┆ list[cat] │
╞═════╪═════════════════╡
│ 1 ┆ ["a", "a", "a"] │
│ 3 ┆ ["b", "b", "b"] │
│ 4 ┆ ["c", "d", "e"] │
└─────┴─────────────────┘
Кроме того, в моем приложении я обнаружил, что выполнение этого — как приведение, так и использование формата — в ленивом режиме возвращает недетерминированное количество строк, что мне кажется ошибкой. Я постараюсь создать общий пример, когда у меня будет время.
Это удивительно. Можешь попробовать df.with_columns(struct = pl.col("values").arr.to_struct()).unique(subset = "struct", maintain_order=True)
или df.groupby(pl.col("values").arr.to_struct().alias("group"), maintain_order=True).first()
@Maturin Использование структуры на самом деле требует сортировки по длине, если длины различаются, поэтому игнорируйте это предложение. Я не могу воспроизвести pl.format
быстрее, в моем тестировании это на несколько величин медленнее. .groupby(col().cast().alias("group"), maintain_order=True).first().drop("group")
у меня получается чуть быстрее, чем cast().unique()
.
Если все списки имеют одинаковую длину, как в вашем примере, вы могли бы (и, возможно, должны) разделить их так, чтобы каждая запись имела свой собственный соответствующий столбец. Хотя иногда вы можете заставить его работать, DataFrames действительно не предназначены для использования с записями, которые сами по себе не являются скалярными. Я предлагаю что-то вроде этого:
In[1]: import polars as pl
data = pl.DataFrame([[1, "a", "a", "a"],
[2, "a", "a", "a"],
[3, "b", "b", "b"],
[4, "c", "d", "e"]],
schema=["id"]+[f"value{i}" for i in range(3)])
print(data)
Out[1]: shape: (4, 4)
┌─────┬────────┬────────┬────────┐
│ id ┆ value0 ┆ value1 ┆ value2 │
│ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ str ┆ str ┆ str │
╞═════╪════════╪════════╪════════╡
│ 1 ┆ a ┆ a ┆ a │
│ 2 ┆ a ┆ a ┆ a │
│ 3 ┆ b ┆ b ┆ b │
│ 4 ┆ c ┆ d ┆ e │
└─────┴────────┴────────┴────────┘
Оттуда прямой вызов data.unique(subset=["value0", "value1", "value2"])
выполнит то, что вы хотите.
Это отличное предложение. Однако в моем приложении списки имеют разную длину.
вы могли бы:
Следующий код является просто демонстративным, сделайте его с ленивым фреймом, чтобы ускорить процесс.
import polars as pl
data = pl.DataFrame({
"id": [1, 2, 3, 4],
"values": [
["a", "a", "a"], # first two rows are duplicated
["a", "a", "a"],
["b", "b", "b"],
["c", "d", "e"]
]
})
print(data)
shape: (4, 2)
┌─────┬─────────────────┐
│ id ┆ values │
│ --- ┆ --- │
│ i64 ┆ list[str] │
╞═════╪═════════════════╡
│ 1 ┆ ["a", "a", "a"] │
│ 2 ┆ ["a", "a", "a"] │
│ 3 ┆ ["b", "b", "b"] │
│ 4 ┆ ["c", "d", "e"] │
└─────┴─────────────────┘
data = data.with_columns(
pl.col('values').arr.join('').alias('tmp')
).unique(
subset='tmp',
maintain_order=True
).drop('tmp')
print(data)
shape: (3, 2)
┌─────┬─────────────────┐
│ id ┆ values │
│ --- ┆ --- │
│ i64 ┆ list[str] │
╞═════╪═════════════════╡
│ 1 ┆ ["a", "a", "a"] │
│ 3 ┆ ["b", "b", "b"] │
│ 4 ┆ ["c", "d", "e"] │
└─────┴─────────────────┘
Использование
pl.format("[{}]", col("values").arr.join(", "))
(которое я взял из одного из ваших ответов на другой пост) вместо приведения к pl.Categorical кажется немного быстрее в моем приложении. Мне все еще больше нравится ваш ответ, так как он чище.