Запросить pandas df, сгруппированный по одной функции, нескольким условиям и вывести его в список

У меня есть следующие панды df (фиктивный df, оригинальный состоит из 100 000 записей).

columns = ['id', 'answer', 'is_correct']
data = [['1','hello','1.0'],
       ['1','hello', '1.0'],
       ['1','bye', '0.0'],
        ['2', 'dog', '0.0'],
        ['2', 'cat', '1.0'],
        ['2', 'dog', '0.0'],
        ['3', 'Milan', '1.0'],
        ['3', 'Paris', '0.0'],
        ['3', 'Paris', '0.0'],
        ['3', 'Milan', '1.0']]
df = pd.DataFrame(columns=columns, data=data)
df

   id   answer  is_correct
0   1   hello   1.0
1   1   hello   1.0
2   1   bye     0.0
3   2   dog     0.0
4   2   cat     1.0
5   2   dog     0.0
6   3   Milan   1.0
7   3   Paris   0.0
8   3   Paris   0.0
9   3   Milan   1.0

Цель состоит в том, чтобы создать список списков на основе условий.

Условия: Для каждого уникального id я хотел бы иметь правильный answer (is_correct == 1.0), затем (псевдо) случайно выбранный answer внутри этого id и, наконец, значение is_correct (1,0 или 0,0) для случайного answer.

[['hello', 'bye', 0.0], ['cat', 'dog', 0.0], ['Milan', 'Milan', 1.0], ...]]

Мне нужно всего два ответа от каждого уникального id. Все идентификаторы состоят из более чем 2 ответов. Ни в одном из столбцов нет NaN.

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

Ответы 3

Я думаю, это то, что вы ищете:

>>> import random

>>> keep = []

>>> for val in df.id.unique():
>>>     temp_keep = []
>>>     temp_df_correct = df[(df.id==val) & (df.is_correct=='1.0')]
>>>     temp_df_notcorrect = df[(df.id==val) & (df.is_correct=='0.0')]

>>>     correct_index = random.choice(temp_df_correct.index)
>>>     temp_keep.append(temp_df_correct.loc[correct_index,'answer'])
>>>     temp_df_correct.drop(correct_index, inplace=True)
    
>>>     new_df = temp_df_correct.append(temp_df_notcorrect, ignore_index=True, sort=False)
>>>     temp_keep.extend(random.choice(new_df[['answer', 'is_correct']].values))
>>>     keep.append(temp_keep)

>>> print(keep)

    [['hello', 'bye', '0.0'], ['cat', 'dog', '0.0'], ['Milan', 'Milan', '1.0']]

Отлично, работает на манекене df! На моем df я получаю ошибку IndexError: Cannot choose from an empty sequence. Однако я дважды проверил, и у меня нет NaN в df. Любая идея, что происхождение может быть?

Exa 15.12.2020 13:48

Я думаю, что нашел проблему, мой фиктивный df начинается с индекса 0, а мой оригинальный df с 1.

Exa 15.12.2020 13:59

Интересно, что если я не добавлю индекс к фиктивному df вручную, предоставленный код не будет работать, потому что он начинается с 0. Затем, если я сделаю df.index = np.arange(1, len(df)+1) индекс начинается с 1, но все равно не работает. Любая идея, почему это так? Я отредактировал вопрос в соответствии с этим.

Exa 15.12.2020 15:07

Что ж, мой друг, единственный раз, когда это не сработает, и причина, по которой вы получаете эту ошибку, заключается в том, что я предположил, что для данного идентификатора всегда будет правильный ответ. Таким образом, в ваших реальных данных существует вероятность того, что для определенного идентификатора все значения is_correct равны 0,0. Теперь ответ, который написал Лиор, в этом случае неверен. Посмотрите на ответ, который он дал. Второй список внутри списка списка — ['собака', 'собака', '0.0']. Всегда ли собака права? Без прав? Если это то, что вы хотите - неправильное значение, если ни одно из них не является правильным? Я могу заставить его сделать это, если хочешь. Ваш звонок.

Amit Amola 15.12.2020 16:27

Эта ошибка обязательно произойдет, если в ваших исходных данных нет is_correct = 1.0 для определенного идентификатора. Если вы хотите, вы можете получить строку «NONE CORRECT», напечатанную обратно, если ни одна из них не верна.

Amit Amola 15.12.2020 16:29

Понятно, надо было отметить/включить это в фиктивный df. Я считаю, что Лиор теперь скорректировал свой ответ на основе вашего комментария, так что это подойдет для меня. Я бы проголосовал за ваши комментарии и ответил бы, но у меня недостаточно репутации.

Exa 15.12.2020 17:22

Все в порядке, Экса, я просто рад узнать, что твоя проблема решена. Приятного обучения.

Amit Amola 15.12.2020 17:27
Ответ принят как подходящий
def filt(grp):
    is_correct = grp['is_correct']=='1.0'
    if is_correct.any():
        sample = grp.sample()
        return [grp['answer'][is_correct].iloc[0],
                sample['answer'].to_list()[0],
                sample['is_correct'].to_list()[0]]

print(df.groupby('id').apply(filt).to_list())  # --> [['hello', 'bye', '0.0'], ['dog', 'dog', '0.0'], ['Milan', 'Milan', '1.0']]

обновление - .apply(bool) был заменен на ==1.0 для обработки строк '1.0' и '0.0'

Круто, работает на манекене df! Интересно, что если я не добавлю индекс к фиктивному df вручную, предоставленный код не будет работать, потому что автоматически сгенерированный индекс начинается с 0, как я предполагаю. Затем, если я делаю df.index = np.arange(1, len(df)+1), индекс начинается с 1, но он все равно не работает. Любая идея, почему это так? Я отредактировал вопрос в соответствии с этим.

Exa 15.12.2020 15:09

нужно добавить iloc[0] в первый возвращаемый элемент. я обновил ответ

Lior Cohen 15.12.2020 15:35

Второй список внутри списка списков говорит ['собака', 'собака', '0.0'], но для любой 'собаки' значение is_correct никогда не равно 1.0 Так это правильно?

Amit Amola 15.12.2020 16:31

Хороший улов, @amit. 0.0 — это строка, а bool('0.0') — True. Исправлено с помощью =='1.0'.

Lior Cohen 15.12.2020 16:44

Я не эксперт по пандам, но в последнее время я использовал его довольно часто. Вы можете сгруппировать свой фрейм данных с помощью следующего кода:

grouped_df = df.groupby(["id"])[["answer", "is_correct"]].agg(list)

После этого каждая строка будет группироваться по id:

                          answer            is_correct
id                                                    
1            [hello, hello, bye]       [1.0, 1.0, 0.0]
2                [dog, cat, dog]       [0.0, 1.0, 0.0]
3   [Milan, Paris, Paris, Milan]  [1.0, 0.0, 0.0, 1.0]

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

for row in grouped_df.iterrows():
    print(row[1]["answer"])
    print(row[1]["is_correct"])

Надеюсь, поможет. Возможно, есть более векторизованный способ сделать это, но, как я уже говорил, я не эксперт.

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