Подсчитайте одинаковые последовательные числа в столбце списка в фрейме данных Polars

У меня есть pl.DataFrame со столбцом, содержащим списки с целыми числами. Мне нужно утверждать, что каждое последовательное целое число появляется максимум два раза подряд.

Например, список, содержащий [1,1,0,-1,1], подойдет, так как число 1 появляется максимум два раза подряд (первые два элемента, за которыми следует ноль).

Этот список должен привести к неверному утверждению: [1,1,1,0,-1] Число 1 появляется три раза подряд.

Вот игрушечный пример, где row2 должно приводить к ошибочному утверждению.

import polars as pl

row1 = [0, 1, -1, -1, 1, 1, -1, 0]
row2 = [1, -1, -1, -1, 0, 0, 1, -1]
df = pl.DataFrame({"list": [row1, row2]})
print(f"row1: {row1}")
print(f"row2: {row2}")
print(df)


row1: [0, 1, -1, -1, 1, 1, -1, 0]
row2: [1, -1, -1, -1, 0, 0, 1, -1]
shape: (2, 1)
┌───────────────┐
│ list          │
│ ---           │
│ list[i64]     │
╞═══════════════╡
│ [0, 1, … 0]   │
│ [1, -1, … -1] │
└───────────────┘

Вы можете использовать pl.Config(fmt_table_cell_list_len=-1), чтобы изменить длину списка. (-1 = неограниченно)

jqurious 27.08.2024 13:27
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
1
50
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вам наверняка понадобится метод для последовательной проверки чисел и фильтрации Dataframe оттуда.

Что-то вроде:

def check_consecutive_repeats(list):
    count = 1
    prev = list[0]
    
    for i in range(1, len(list)):
        if list[i] == prev:
            count += 1
            if count > 2:
                return False
        else:
            count = 1
            prev = list[i]
    
    return True

Это будет перебирать список и проверять, повторяется ли данный символ более 2 раз, если да, то он вернет False.

Отсюда вы можете решить, что делать со списком, который не удался.

Другие решения вы также можете найти здесь.

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

Можно использовать следующее.

  1. Выполните кодирование серий списка с помощью pl.Expr.rle. Это создает список структур. Каждая структура содержит (уникальное) значение списка и соответствующую длину выполнения.

  2. Проверьте, не превышает ли максимальная длина пробега в списке 2.

  3. Убедитесь, что результат имеет тип bool, выбрав первый (и единственный) элемент в результирующем списке (используя pl.Expr.list.first).

df.with_columns(
    ok=pl.col("list").list.eval(
        pl.element().rle().struct.field("len").max() <= 2
    ).list.first()
)
shape: (2, 2)
┌──────────────────────────────┬───────┐
│ list                         ┆ ok    │
│ ---                          ┆ ---   │
│ list[i64]                    ┆ bool  │
╞══════════════════════════════╪═══════╡
│ [0, 1, -1, -1, 1, 1, -1, 0]  ┆ true  │
│ [1, -1, -1, -1, 0, 0, 1, -1] ┆ false │
└──────────────────────────────┴───────┘

Выполнение всего этого в pl.Expr.list.eval можно избежать, развернув список. Затем необходима оконная функция ( pl.Expr.over), чтобы обеспечить вычисление максимума отдельно для каждого списка.

max_run_length = pl.col("list").explode().rle().struct.field("len").max().over(pl.int_range(pl.len()))
df.with_columns(passed=max_run_length <= 2)

Результат будет тот же.

pl.Expr.rle довольно необычно. Я действительно начинаю ценить polars :-) Спасибо за вашу поддержку!!
Andi 27.08.2024 17:02

Использование map_elements с генератором и коротким замыканием:

N = 2

df.with_columns(
    valid=pl.col('list').map_elements(
        lambda x: all(
            any(x[i] != x[i+1:i+N+1]) for i in range(len(x)-N+1)
        ), return_dtype=pl.Boolean
    )
)

Выход:

┌───────────────┬───────┐
│ list          ┆ valid │
│ ---           ┆ ---   │
│ list[i64]     ┆ bool  │
╞═══════════════╪═══════╡
│ [0, 1, … 0]   ┆ true  │
│ [1, -1, … -1] ┆ false │
└───────────────┴───────┘

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