Как я могу настроить сортировку столбца списка, используя другой столбец списка?

у меня есть стол

| user     | list_1   | list_2   | list_3   |  rank   |
| -------- | -------- | -------- | -------- |-------- |
|   xxx    |  [1,3,5] |  [8,3,5] |  [6,7,8] | [1,2,3] |
|   yyy    |  [4,9,5] |  [3,4,5] |  [7,8,3] | [1,3,2] |
|   zzz    |  [4,6,1] |  [9,3,6] |  [4,3,2] | [2,3,1] |

Столбец rank является производным от ранга столбца list_1. Я хотел бы отсортировать остальные столбцы list_2, list_3, используя столбец ранга.

Желаемый результат должен быть

| user | list_1  | list_2  | list_3  |  rank   |
+------+---------+---------+---------+---------+
| xxx  | [1,3,5] | [8,3,5] | [6,7,8] | [1,2,3] |
| yyy  | [4,5,9] | [3,5,4] | [7,3,8] | [1,3,2] |
| zzz  | [1,4,6] | [6,9,3] | [2,4,3] | [2,3,1] |

я пробовал различные функции .list, но думаю, что они не могут принимать аргументы по строкам

Есть ли какая-нибудь функция в полярах, которая может это сделать? Очень признателен

import polars as pl

data = {
    "user": ["xxx", "yyy", "zzz"],
    "list_1": [[1, 3, 5], [4, 9, 5], [4, 6, 1]],
    "list_2": [[8, 3, 5], [3, 4, 5], [9, 3, 6]],
    "list_3": [[6, 7, 8], [7, 8, 3], [4, 3, 2]],
    "rank": [[1, 2, 3], [1, 3, 2], [2, 3, 1]]
}

df = pl.DataFrame(data)

print(df)

Что-то не так с вашим примером: либо ранг zzz неверен, либо ваш вывод неверен.

mozway 25.06.2024 11:38
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
1
68
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

полярники

Вы можете разобрать, отсортировать по группам пользователей, а затем объединить обратно в списки:

df = pl.DataFrame({'user': ['xxx', 'yyy', 'zzz'],
                   'list_1': [[1, 3, 5], [4, 9, 5], [4, 6, 1]],
                   'list_2': [[8, 3, 5], [3, 4, 5], [9, 3, 6]],
                   'list_3': [[6, 7, 8], [7, 8, 3], [4, 3, 2]],
                   'rank': [[1, 2, 3], [1, 3, 2], [2, 3, 1]]})

cols = ['list_1', 'list_2', 'list_3', 'rank']

rank = df['rank']

out = (df.explode(cols).select(pl.all().sort_by('rank').over('user'))
         .group_by('user', maintain_order=True).agg(pl.col(cols))
         .with_columns(rank=rank)
      )

Выход:

┌──────┬───────────┬───────────┬───────────┬───────────┐
│ user ┆ list_1    ┆ list_2    ┆ list_3    ┆ rank      │
│ ---  ┆ ---       ┆ ---       ┆ ---       ┆ ---       │
│ str  ┆ list[i64] ┆ list[i64] ┆ list[i64] ┆ list[i64] │
╞══════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ xxx  ┆ [1, 3, 5] ┆ [8, 3, 5] ┆ [6, 7, 8] ┆ [1, 2, 3] │
│ yyy  ┆ [4, 5, 9] ┆ [3, 5, 4] ┆ [7, 3, 8] ┆ [1, 3, 2] │
│ zzz  ┆ [1, 4, 6] ┆ [6, 9, 3] ┆ [2, 4, 3] ┆ [2, 3, 1] │
└──────┴───────────┴───────────┴───────────┴───────────┘

оригинальный ответ

чистый питон

Предполагая списки Python, вам придется перебирать их и переупорядочивать:

cols = ['list_1', 'list_2', 'list_3']

for c in cols:
    df[c] = [[l[i-1] for i in r] for l, r in zip(df[c], df['rank'])]

Выход:

 user     list_1     list_2     list_3       rank
0  xxx  [1, 3, 5]  [8, 3, 5]  [6, 7, 8]  [1, 2, 3]
1  yyy  [4, 5, 9]  [3, 5, 4]  [7, 3, 8]  [1, 3, 2]
2  zzz  [6, 1, 4]  [3, 6, 9]  [3, 2, 4]  [2, 3, 1]

Обратите внимание, что в вашем примере ранги кажутся неверными. Если вам нужно вычислить ранг:

cols = ['list_1', 'list_2', 'list_3']

df['rank'] = [(np.argsort(x)+1).tolist() for x in df['list_1']]

for c in cols:
    df[c] = [[l[i-1] for i in r] for l, r in zip(df[c], df['rank'])]

Выход:

  user     list_1     list_2     list_3       rank
0  xxx  [1, 3, 5]  [8, 3, 5]  [6, 7, 8]  [1, 2, 3]
1  yyy  [4, 5, 9]  [3, 5, 4]  [7, 3, 8]  [1, 3, 2]
2  zzz  [1, 4, 6]  [6, 9, 3]  [2, 4, 3]  [3, 1, 2]

бестолковый

Если весь ваш список имеет одинаковый размер, вы также можете использовать промежуточный 3D numpy массив, argsort и take_along_axis:

a = np.array(df[cols].to_numpy().tolist())
order = np.argsort(a[:, 0], axis=1)
df['rank'] = (order+1).tolist()
df[cols] = np.take_along_axis(a, a[:, [0]].argsort(axis=-1), axis=-1).tolist()

Выход:

  user     list_1     list_2     list_3       rank
0  xxx  [1, 3, 5]  [8, 3, 5]  [6, 7, 8]  [1, 2, 3]
1  yyy  [4, 5, 9]  [3, 5, 4]  [7, 3, 8]  [1, 3, 2]
2  zzz  [1, 4, 6]  [6, 9, 3]  [2, 4, 3]  [3, 1, 2]

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

benedictine_cumbersome 25.06.2024 11:59

@benedictine_cumbersome К сожалению, я пропустил тег Polars; Можете ли вы предоставить минимальный воспроизводимый пример в виде кода?

mozway 25.06.2024 12:00

Я новичок в этом. Считается ли приведенный выше фрейм данных MRE?

benedictine_cumbersome 25.06.2024 12:15

@benedictine_cumbersome да, спасибо, я обновил свой ответ. Также я бы рекомендовал опубликовать текстовый вывод поляров, чтобы сразу было понятно, что вы используете поляры;)

mozway 25.06.2024 12:15

раздел полярников заработал! Большое спасибо

benedictine_cumbersome 25.06.2024 12:18
Ответ принят как подходящий

Альтернативой решению с использованием шаблона explode(), group_by(), agg() можно использовать pl.Expr.list.gather, чтобы выбирать элементы из каждого списка по порядку.

Для этого мы преобразуем ранги, используя pl.Expr.list.eval и pl.Expr.arg_sort, чтобы получить список индексов, выбирающих элементы в порядке, предложенном rank.

cols = ["list_1", "list_2", "list_3"]

df.with_columns(
    pl.col(cols).list.gather(
        pl.col("rank").list.eval(pl.element().arg_sort())
    )
)
shape: (3, 5)
┌──────┬───────────┬───────────┬───────────┬───────────┐
│ user ┆ list_1    ┆ list_2    ┆ list_3    ┆ rank      │
│ ---  ┆ ---       ┆ ---       ┆ ---       ┆ ---       │
│ str  ┆ list[i64] ┆ list[i64] ┆ list[i64] ┆ list[i64] │
╞══════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ xxx  ┆ [1, 3, 5] ┆ [8, 3, 5] ┆ [6, 7, 8] ┆ [1, 2, 3] │
│ yyy  ┆ [4, 5, 9] ┆ [3, 5, 4] ┆ [7, 3, 8] ┆ [1, 3, 2] │
│ zzz  ┆ [1, 4, 6] ┆ [6, 9, 3] ┆ [2, 4, 3] ┆ [2, 3, 1] │
└──────┴───────────┴───────────┴───────────┴───────────┘

Хороший вариант, но я бы, наверное, изменил его на pl.col("rank").list.eval(pl.element() - 1. Мне просто кажется более аккуратным. arg_sort() сработало бы на текущем примере, но сработает и, например, на rank = [-100, 100, 200] instead of [1,2,3], что, я бы сказал, не является намерением.

Roman Pekar 25.06.2024 18:36

@RomanPekar Правда... Сначала у меня было pl.element() - 1 локально, но я переключился на более общее решение. Однако простое уменьшение ранга, вероятно, также будет гораздо более эффективным. Я отредактирую ответ, упомянув альтернативу, как только перестану пользоваться мобильным телефоном.

Hericks 25.06.2024 18:43

Если вы немного скорректируете свой расчет rank, чтобы он основывался на 0

  • list.eval() для перебора элементов списка.
  • Rank() для расчета ранга.
df = df.with_columns(
    rank = pl.col.list_1.list.eval(pl.element().rank().cast(pl.Int32) - 1)
)

┌──────┬───────────┬───────────┬───────────┬───────────┐
│ user ┆ list_1    ┆ list_2    ┆ list_3    ┆ rank      │
│ ---  ┆ ---       ┆ ---       ┆ ---       ┆ ---       │
│ str  ┆ list[i64] ┆ list[i64] ┆ list[i64] ┆ list[i32] │
╞══════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ xxx  ┆ [1, 3, 5] ┆ [8, 3, 5] ┆ [6, 7, 8] ┆ [0, 1, 2] │
│ yyy  ┆ [4, 9, 5] ┆ [3, 4, 5] ┆ [7, 8, 3] ┆ [0, 2, 1] │
│ zzz  ┆ [4, 6, 1] ┆ [9, 3, 6] ┆ [4, 3, 2] ┆ [1, 2, 0] │
└──────┴───────────┴───────────┴───────────┴───────────┘
  • list.gather() для изменения положения элементов в соответствии с индексами в столбце rank.
cols = ["list_1", "list_2", "list_3"]

df.with_columns(
    pl.col(cols).list.gather(pl.col.rank)
)

┌──────┬───────────┬───────────┬───────────┬───────────┐
│ user ┆ list_1    ┆ list_2    ┆ list_3    ┆ rank      │
│ ---  ┆ ---       ┆ ---       ┆ ---       ┆ ---       │
│ str  ┆ list[i64] ┆ list[i64] ┆ list[i64] ┆ list[i32] │
╞══════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ xxx  ┆ [1, 3, 5] ┆ [8, 3, 5] ┆ [6, 7, 8] ┆ [0, 1, 2] │
│ yyy  ┆ [4, 5, 9] ┆ [3, 5, 4] ┆ [7, 3, 8] ┆ [0, 2, 1] │
│ zzz  ┆ [6, 1, 4] ┆ [3, 6, 9] ┆ [3, 2, 4] ┆ [1, 2, 0] │
└──────┴───────────┴───────────┴───────────┴───────────┘

Альтернативно вы можете настроить существующие rank данные и работать с исходным фреймом данных:

df.with_columns(
    pl.col(cols).list.gather(
        pl.col("rank").list.eval(pl.element() - 1)
    )
)

┌──────┬───────────┬───────────┬───────────┬───────────┐
│ user ┆ list_1    ┆ list_2    ┆ list_3    ┆ rank      │
│ ---  ┆ ---       ┆ ---       ┆ ---       ┆ ---       │
│ str  ┆ list[i64] ┆ list[i64] ┆ list[i64] ┆ list[i64] │
╞══════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ xxx  ┆ [1, 3, 5] ┆ [8, 3, 5] ┆ [6, 7, 8] ┆ [1, 2, 3] │
│ yyy  ┆ [4, 5, 9] ┆ [3, 5, 4] ┆ [7, 3, 8] ┆ [1, 3, 2] │
│ zzz  ┆ [6, 1, 4] ┆ [3, 6, 9] ┆ [3, 2, 4] ┆ [2, 3, 1] │
└──────┴───────────┴───────────┴───────────┴───────────┘

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