Анализ числовых данных с разделителем тысяч в полярах

У меня есть файл tsv, содержащий целые числа с разделителями тысяч. Я пытаюсь прочитать его, используя polars==1.6.0, кодировка utf-16.

from io import BytesIO
import polars as pl

data = BytesIO(
"""
Id\tA\tB
1\t537\t2,288
2\t325\t1,047
3\t98\t194
""".encode("utf-16")
)

df = pl.read_csv(data, encoding = "utf-16", separator = "\t")
print(df)

Я не могу понять, как заставить поляры обрабатывать столбец «B» как целое число, а не как строку, и я также не могу найти чистый способ приведения его к целому числу.

shape: (3, 3)
┌────────┬─────┬───────┐
│ Id     ┆ A   ┆ B     │
│ ---    ┆ --- ┆ ---   │
│ i64    ┆ i64 ┆ str   │
╞════════╪═════╪═══════╡
│ 1      ┆ 537 ┆ 2,288 │
│ 2      ┆ 325 ┆ 1,047 │
│ 3      ┆ 98  ┆ 194   │
└────────┴─────┴───────┘

приведение не удается, как и явная передача схемы. Я также пробовал использовать str.strip_chars, и чтобы удалить запятую, вместо этого я использую str.replace_all.

df = df.with_columns(
    pl.col("B").str.strip_chars(",").alias("B_strip_chars"),
    pl.col("B").str.replace_all("[^0-9]", "").alias("B_replace"),
)
print(df)
shape: (3, 5)
┌────────┬─────┬───────┬───────────────┬───────────┐
│ Id     ┆ A   ┆ B     ┆ B_strip_chars ┆ B_replace │
│ ---    ┆ --- ┆ ---   ┆ ---           ┆ ---       │
│ i64    ┆ i64 ┆ str   ┆ str           ┆ str       │
╞════════╪═════╪═══════╪═══════════════╪═══════════╡
│ 1      ┆ 537 ┆ 2,288 ┆ 2,288         ┆ 2288      │
│ 2      ┆ 325 ┆ 1,047 ┆ 1,047         ┆ 1047      │
│ 3      ┆ 98  ┆ 194   ┆ 194           ┆ 194       │
└────────┴─────┴───────┴───────────────┴───────────┘

Кроме того, чтобы это работало в целом, мне нужно убедиться, что read_csv не пытается вывести типы для каких-либо столбцов, чтобы я мог преобразовать их все вручную (любой числовой столбец со значением> 999 будет содержать запятую)

не уверен, что это лучший способ, но простой .with_columns(pl.col.B.str.replace(",", "").cast(pl.Int32)) работает

Roman Pekar 29.08.2024 08:07

также pl.read_csv(..., use_pyarrow=True) работает

Roman Pekar 29.08.2024 08:11

Я попробовал use_pyarrow, и, похоже, это не сработало, по крайней мере, при чтении из реального файла — мой игрушечный пример может быть не на 100% таким же. Я предполагал, что замена не удастся, если их будет больше 1 "," (т. е. 1 000 000), но я не пробовал.

David Waterworth 29.08.2024 08:44
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
5
3
55
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Чтобы разрешить использование нескольких разделителей ,, используйте .str.replace_all:

df = df.with_columns(pl.col('B').str.replace_all(",", "").cast(pl.Int64))

что дает для примера данных:

   shape: (3, 3)
┌─────┬─────┬──────┐
│ Id  ┆ A   ┆ B    │
│ --- ┆ --- ┆ ---  │
│ i64 ┆ i64 ┆ i64  │
╞═════╪═════╪══════╡
│ 1   ┆ 537 ┆ 2288 │
│ 2   ┆ 325 ┆ 1047 │
│ 3   ┆ 98  ┆ 194  │
└─────┴─────┴──────┘

Чтобы сделать этот подход более общим, вместо pl.col('B') вы можете использовать pl.col(pl.String), чтобы он перехватывал любой столбец, который проходил в виде строки. Помимо этого вам может потребоваться обработка ошибок, но это зависит от данных.

Dean MacGregor 29.08.2024 13:15

Спасибо - я думаю, однако, чтобы сделать его полностью универсальным, мне нужно будет заставить все столбцы быть строковыми, когда я читаю CSV - в противном случае я "случайно" получу столбцы str или int в зависимости от того, содержат ли данные значение> 999 или нет

David Waterworth 30.08.2024 00:13

Если ваши исходные данные имеют формат utf-16 (или что-то еще, кроме utf-8), то Polars преобразует их в utf-8 через Python. Поскольку это в любом случае должно произойти, возможно, лучше выполнить это преобразование самостоятельно и заменить знаки «,» в середине, чтобы встроенная программа чтения csv поляров анализировала данные как числа в начале read_csv, а не на последующем этапе.

data.seek(0)
pl.read_csv(data.read().decode('utf-16').replace(',','').encode('utf-8'), separator = "\t")

Просто чтобы подчеркнуть, что если ваши исходные данные уже имеют формат utf-8, то использование Python для replace почти наверняка медленнее, чем ответ @user19077881. Делайте это только в том случае, если ваш источник не utf-8, потому что Polars все равно преобразует его в utf-8 в Python. Конечно, если у вас есть столбцы, которые на самом деле должны быть строками с запятыми, это не сработает, потому что они не знают разницы.

Другие вопросы по теме