Как эффективно устанавливать значения столбцов на основе нескольких других столбцов

У меня есть фрейм данных, который содержит «дублированные» данные во всех столбцах, кроме одного, называемого источником. Я сопоставляю эти записи по одной для каждого источника в группы. Пример данных для такого кадра данных:

id,str_id,partition_number,source,type,state,quantity,price,m_group,m_status
1,s1_1,111,1,A,1,10,100.0,,0
2,s1_2,111,1,A,1,10,100.0,,0
3,s1_3,222,1,B,2,20,150.0,,0
4,s1_4,333,1,C,1,30,200.0,,0
5,s1_5,111,1,A,1,10,100.0,,0
6,s1_6,111,1,A,1,10,100.0,,0
7,s2_1,111,5,A,1,10,100.0,,0
8,s2_2,111,5,A,1,10,100.0,,0
9,s2_3,111,5,A,1,10,100.0,,0
10,s2_4,222,5,B,2,20,150.0,,0
11,s2_5,444,5,D,1,40,250.0,,0
12,s3_1,111,6,A,1,10,100.0,,0
13,s3_2,111,6,A,1,10,100.0,,0
14,s3_3,111,6,A,1,10,100.0,,0
15,s3_4,222,6,B,2,20,150.0,,0
16,s3_5,444,6,D,1,40,250.0,,0
17,s3_6,333,6,C,1,30,200.0,,0

Загружено в фрейм данных:

┌─────┬──────────┬──────────┬──────────┬────────┬──────┬──────────┬──────────┬──────────┬──────────┐
│ id  ┆ str_id   ┆ part_    ┆ source   ┆ type   ┆ stat ┆ quantity ┆ price    ┆ m_group  ┆ m_status │
│ --- ┆          ┆ number   ┆          ┆ ---    ┆ ---  ┆ ---      ┆ ---      ┆          ┆          │ 
│ i64 ┆ ---      ┆ ---      ┆ ---      ┆ str    ┆ i64  ┆ i64      ┆ f64      ┆ ---      ┆ ---      │
│     ┆ str      ┆ str      ┆ i64      ┆        ┆      ┆          ┆          ┆         ┆       │
╞═════╪══════════╪══════════╪══════════╪══════╪══════╪══════════╪═════════╪═════════╪══════════╡
│ 1   ┆ s1_1     ┆ 111      ┆ 1        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
│ 2   ┆ s1_2     ┆ 111      ┆ 1        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
│ 3   ┆ s1_3     ┆ 222      ┆ 1        ┆ B      ┆ 2    ┆ 20.      ┆ 150.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
│ 4   ┆ s1_4     ┆ 333      ┆ 1        ┆ C      ┆ 1    ┆ 30.      ┆ 200.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
│ 5   ┆ s1_5     ┆ 111      ┆ 1        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
│ 6   ┆ s1_6     ┆ 111      ┆ 1        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
│ 7   ┆ s2_1     ┆ 111      ┆ 5        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
│ 8   ┆ s2_2     ┆ 111      ┆ 5        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
│ 9   ┆ s2_3     ┆ 111      ┆ 5        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
│ 10  ┆ s2_4     ┆ 222      ┆ 5        ┆ B      ┆ 2    ┆ 20.      ┆ 150.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
│ 11  ┆ s2_5     ┆ 444      ┆ 5        ┆ D      ┆ 1    ┆ 40.      ┆ 250.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
│ 12  ┆ s3_1     ┆ 111      ┆ 6        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
│ 13  ┆ s3_2     ┆ 111      ┆ 6        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
│ 14  ┆ s3_3     ┆ 111      ┆ 6        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
│ 15  ┆ s3_4     ┆ 222      ┆ 6        ┆ B      ┆ 2    ┆ 20.      ┆ 150.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
│ 16  ┆ s3_5     ┆ 444      ┆ 6        ┆ D      ┆ 1    ┆ 40.      ┆ 250.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
│ 17  ┆ s3_6     ┆ 333      ┆ 6        ┆ C      ┆ 1    ┆ 30.      ┆ 200.0000 ┆ []     ┆ []        │
│     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
└─────┴──────────┴──────────┴──────────┴────────┴──────┴──────────┴──────────┴──────────┴──────────┘

После того, как я сопоставлю их, у меня есть выходной фрейм данных, содержащий три столбца типа [список], которые объединяют идентификаторы, str_ids и источники в группы «дублированных» записей:

┌─────────────┬──────────────────────────┬────────────────┐
│ id          ┆ str_id                   ┆ source         │
│ ---         ┆ ---                      ┆ ---            │
│ list[i64]   ┆ list[str]                ┆ list[i64]      │
╞═════════════╪══════════════════════════╪════════════════╡
│ [5, 9, 14]  ┆ ["s1_5", "s2_3", "s3_3"] ┆ [1, 5, 6]      │
│ [2, 8, 13]  ┆ ["s1_2", "s2_2", "s3_2"] ┆ [1, 5, 6]      │
│ [6]         ┆ ["s1_6"]                 ┆ [1]            │
│ [3, 10, 15] ┆ ["s1_3", "s2_4", "s3_4"] ┆ [1, 5, 6]      │
│ [1, 7, 12]  ┆ ["s1_1", "s2_1", "s3_1"] ┆ [1, 5, 6]      │
│ [11, 16]    ┆ ["s2_5", "s3_5"]         ┆ [5, 6]         │
│ [4, 17]     ┆ ["s1_4", "s3_6"]         ┆ [1, 6]         │
└─────────────┴──────────────────────────┴────────────────┘

Какой наиболее оптимальный способ:

  1. обновите значения для столбцов m_status в исходном кадре данных, например, для каждой записи, которая имеет группу размером не менее 2, установите для значения m_status значения противоположных источников, если источник == 1, в противном случае установите значение m_status на значение 1, если в группе есть источник 1.

    поэтому результат будет:

    
    ┌─────┬──────────┬──────────┬──────────┬────────┬──────┬──────────┬──────────┬──────────┬──────────┐
    │ id  ┆ str_id   ┆ part_    ┆ source   ┆ type   ┆ stat ┆ quantity ┆ price    ┆ m_group  ┆ m_status │
    │ --- ┆          ┆ number   ┆          ┆ ---    ┆ ---  ┆ ---      ┆ ---      ┆          ┆          │ 
    │ i64 ┆ ---      ┆ ---      ┆ ---      ┆ str    ┆ i64  ┆ i64      ┆ f64      ┆ ---      ┆ ---      │
    │     ┆ str      ┆ str      ┆ i64      ┆        ┆      ┆          ┆          ┆         ┆       │
    ╞═════╪══════════╪══════════╪══════════╪══════╪══════╪══════════╪═════════╪═════════╪══════════╡
    │ 1   ┆ s1_1     ┆ 111      ┆ 1        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ [5,6]        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    │ 2   ┆ s1_2     ┆ 111      ┆ 1        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ [5,6]        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    │ 3   ┆ s1_3     ┆ 222      ┆ 1        ┆ B      ┆ 2    ┆ 20.      ┆ 150.0000 ┆ []     ┆ [5,6]        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    │ 4   ┆ s1_4     ┆ 333      ┆ 1        ┆ C      ┆ 1    ┆ 30.      ┆ 200.0000 ┆ []     ┆ [6]        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    │ 5   ┆ s1_5     ┆ 111      ┆ 1        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ [5,6]        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    │ 6   ┆ s1_6     ┆ 111      ┆ 1        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ []        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    │ 7   ┆ s2_1     ┆ 111      ┆ 5        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ [1]        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    │ 8   ┆ s2_2     ┆ 111      ┆ 5        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ [1]        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    │ 9   ┆ s2_3     ┆ 111      ┆ 5        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ [1]        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    │ 10  ┆ s2_4     ┆ 222      ┆ 5        ┆ B      ┆ 2    ┆ 20.      ┆ 150.0000 ┆ []     ┆ [1]        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    │ 11  ┆ s2_5     ┆ 444      ┆ 5        ┆ D      ┆ 1    ┆ 40.      ┆ 250.0000 ┆ []     ┆ []        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    │ 12  ┆ s3_1     ┆ 111      ┆ 6        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ [1]        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    │ 13  ┆ s3_2     ┆ 111      ┆ 6        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ [1]        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    │ 14  ┆ s3_3     ┆ 111      ┆ 6        ┆ A      ┆ 1    ┆ 10.      ┆ 100.0000 ┆ []     ┆ [1]        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    │ 15  ┆ s3_4     ┆ 222      ┆ 6        ┆ B      ┆ 2    ┆ 20.      ┆ 150.0000 ┆ []     ┆ [1]        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    │ 16  ┆ s3_5     ┆ 444      ┆ 6        ┆ D      ┆ 1    ┆ 40.      ┆ 250.0000 ┆ []     ┆ []        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    │ 17  ┆ s3_6     ┆ 333      ┆ 6        ┆ C      ┆ 1    ┆ 30.      ┆ 200.0000 ┆ []     ┆ [1]        │
    │     ┆          ┆          ┆          ┆        ┆      ┆          ┆      000 ┆        ┆          │
    └─────┴──────────┴──────────┴──────────┴────────┴──────┴──────────┴──────────┴──────────┴──────────┘
    
  2. создайте совершенно новый фрейм данных (может быть в другом порядке), который содержит идентификаторы, str_ids и m_status так же, как указано выше. Таким образом, мне не пришлось бы искать исходный фрейм данных (но если у меня есть идентификаторы, это не должно быть дорого), и я мог бы просто выполнить итерацию, чтобы создать новый.

Мое решение на данный момент:


df_out = df_out.select("id", "str_id", "source")
m_status_mapping = {}
for ids, str_ids, sources in df_out.iter_rows():
    for i, id_ in enumerate(ids):
        opposite_sources = [str(rep) for j, s in enumerate(sources) if j != i]
        m_status_mapping[id_] = ','.join(opposite_sources)

df = df_original.with_columns(
    pl.col("id").replace(m_status_mapping).alias("m_status")
)
df = df.with_columns(pl.col("m_status").str.split(","))
df.select("id", "str_id", "m_status")

В результате получается следующий результат:

id  str_id  m_status
i64 str     list[str]
1   "s1_1"  ["5", "6"]
2   "s1_2"  ["5", "6"]
3   "s1_3"  ["5", "6"]
4   "s1_4"  ["6"]
5   "s1_5"  ["5", "6"]
6   "s1_6"  [""]
7   "s2_1"  ["1", "6"]
8   "s2_2"  ["1", "6"]
9   "s2_3"  ["1", "6"]
10  "s2_4"  ["1", "6"]
11  "s2_5"  ["6"]
12  "s3_1"  ["1", "5"]
13  "s3_2"  ["1", "5"]
14  "s3_3"  ["1", "5"]
15  "s3_4"  ["1", "5"]
16  "s3_5"  ["5"]
17  "s3_6"  ["1"]

Это почти работает, я получаю слишком много источников в m_status для строк с source != 1. Кроме того, это, вероятно, ужасно с точки зрения эффективности, должен быть гораздо лучший способ сделать это.

Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
4
0
105
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Использование фрейма данных с агрегированными повторяющимися записями:

  • list.len() для проверки длины списка.
  • list.contains(), чтобы проверить, присутствует ли 1.
  • list.set_difference() чтобы получить список элементов, отличных от 1.
  • взорвать(), чтобы разбить списки обратно на строки.
  • когда/то для условного создания результирующего m_status столбца.
(
    df.with_columns(
        l = pl.col.source.len(),
        has1 = pl.col.source.list.contains(1),
        excl1 = pl.col.source.list.set_difference([1])
    ).explode(pl.col("id","str_id","source"))
    .select(
        pl.col("id","str_id","source"),
        m_status = 
        pl.when(pl.col.l >= 2, pl.col.source == 1).then(pl.col.excl1)
        .when(pl.col.l >= 2, pl.col.has1).then([1])
        .otherwise([])        
    )
    .sort("id")
)

┌─────┬────────┬────────┬───────────┐
│ id  ┆ str_id ┆ source ┆ m_status  │
│ --- ┆ ---    ┆ ---    ┆ ---       │
│ i64 ┆ str    ┆ i64    ┆ list[i64] │
╞═════╪════════╪════════╪═══════════╡
│ 1   ┆ s1_1   ┆ 1      ┆ [6, 5]    │
│ 2   ┆ s1_2   ┆ 1      ┆ [6, 5]    │
│ 3   ┆ s1_3   ┆ 1      ┆ [6, 5]    │
│ 4   ┆ s1_4   ┆ 1      ┆ [6]       │
│ 5   ┆ s1_5   ┆ 1      ┆ [6, 5]    │
│ 6   ┆ s1_6   ┆ 1      ┆ []        │
│ 7   ┆ s2_1   ┆ 5      ┆ [1]       │
│ 8   ┆ s2_2   ┆ 5      ┆ [1]       │
│ 9   ┆ s2_3   ┆ 5      ┆ [1]       │
│ 10  ┆ s2_4   ┆ 5      ┆ [1]       │
│ 11  ┆ s2_5   ┆ 5      ┆ []        │
│ 12  ┆ s3_1   ┆ 6      ┆ [1]       │
│ 13  ┆ s3_2   ┆ 6      ┆ [1]       │
│ 14  ┆ s3_3   ┆ 6      ┆ [1]       │
│ 15  ┆ s3_4   ┆ 6      ┆ [1]       │
│ 16  ┆ s3_5   ┆ 6      ┆ []        │
│ 17  ┆ s3_6   ┆ 6      ┆ [1]       │
└─────┴────────┴────────┴───────────┘

Просто дополнение: именно так вы можете агрегировать «дублирующиеся» записи.

(
    df
    .with_columns(i = pl.int_range(pl.len()).over("source","partition_number"))
    .group_by("i","partition_number", maintain_order=True)
    .agg("id","str_id","source")
    .drop("i","partition_number")
)

┌─────────────┬──────────────────────────┬───────────┐
│ id          ┆ str_id                   ┆ source    │
│ ---         ┆ ---                      ┆ ---       │
│ list[i64]   ┆ list[str]                ┆ list[i64] │
╞═════════════╪══════════════════════════╪═══════════╡
│ [1, 7, 12]  ┆ ["s1_1", "s2_1", "s3_1"] ┆ [1, 5, 6] │
│ [2, 8, 13]  ┆ ["s1_2", "s2_2", "s3_2"] ┆ [1, 5, 6] │
│ [3, 10, 15] ┆ ["s1_3", "s2_4", "s3_4"] ┆ [1, 5, 6] │
│ [4, 17]     ┆ ["s1_4", "s3_6"]         ┆ [1, 6]    │
│ [5, 9, 14]  ┆ ["s1_5", "s2_3", "s3_3"] ┆ [1, 5, 6] │
│ [6]         ┆ ["s1_6"]                 ┆ [1]       │
│ [11, 16]    ┆ ["s2_5", "s3_5"]         ┆ [5, 6]    │
└─────────────┴──────────────────────────┴───────────┘

Используя эту агрегацию, вы также можете рассчитывать m_status по группам без агрегирования.

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

(
    df
    .with_columns(i = pl.int_range(pl.len()).over("source","partition_number"))
    .with_columns(
        l = pl.len().over("partition_number","i"),
        has1 = (pl.col.source == 1).any().over("partition_number","i"),
        excl1 = pl.col.source.filter(pl.col.source != 1).over("partition_number","i", mapping_strategy = "join")
    )
    .select(
        pl.col("id","str_id","source"),
        m_status = 
        pl.when(pl.col.l >= 2, pl.col.source == 1).then(pl.col.excl1)
        .when(pl.col.l >= 2, pl.col.has1).then([1])
        .otherwise([])        
    )    
)

┌─────┬────────┬────────┬───────────┐
│ id  ┆ str_id ┆ source ┆ m_status  │
│ --- ┆ ---    ┆ ---    ┆ ---       │
│ i64 ┆ str    ┆ i64    ┆ list[i64] │
╞═════╪════════╪════════╪═══════════╡
│ 1   ┆ s1_1   ┆ 1      ┆ [5, 6]    │
│ 2   ┆ s1_2   ┆ 1      ┆ [5, 6]    │
│ 3   ┆ s1_3   ┆ 1      ┆ [5, 6]    │
│ 4   ┆ s1_4   ┆ 1      ┆ [6]       │
│ 5   ┆ s1_5   ┆ 1      ┆ [5, 6]    │
│ 6   ┆ s1_6   ┆ 1      ┆ []        │
│ 7   ┆ s2_1   ┆ 5      ┆ [1]       │
│ 8   ┆ s2_2   ┆ 5      ┆ [1]       │
│ 9   ┆ s2_3   ┆ 5      ┆ [1]       │
│ 10  ┆ s2_4   ┆ 5      ┆ [1]       │
│ 11  ┆ s2_5   ┆ 5      ┆ []        │
│ 12  ┆ s3_1   ┆ 6      ┆ [1]       │
│ 13  ┆ s3_2   ┆ 6      ┆ [1]       │
│ 14  ┆ s3_3   ┆ 6      ┆ [1]       │
│ 15  ┆ s3_4   ┆ 6      ┆ [1]       │
│ 16  ┆ s3_5   ┆ 6      ┆ []        │
│ 17  ┆ s3_6   ┆ 6      ┆ [1]       │
└─────┴────────┴────────┴───────────┘

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