У меня есть следующие панды 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.
Я думаю, это то, что вы ищете:
>>> 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 начинается с индекса 0, а мой оригинальный df с 1.
Интересно, что если я не добавлю индекс к фиктивному df вручную, предоставленный код не будет работать, потому что он начинается с 0. Затем, если я сделаю df.index = np.arange(1, len(df)+1) индекс начинается с 1, но все равно не работает. Любая идея, почему это так? Я отредактировал вопрос в соответствии с этим.
Что ж, мой друг, единственный раз, когда это не сработает, и причина, по которой вы получаете эту ошибку, заключается в том, что я предположил, что для данного идентификатора всегда будет правильный ответ. Таким образом, в ваших реальных данных существует вероятность того, что для определенного идентификатора все значения is_correct равны 0,0. Теперь ответ, который написал Лиор, в этом случае неверен. Посмотрите на ответ, который он дал. Второй список внутри списка списка — ['собака', 'собака', '0.0']. Всегда ли собака права? Без прав? Если это то, что вы хотите - неправильное значение, если ни одно из них не является правильным? Я могу заставить его сделать это, если хочешь. Ваш звонок.
Эта ошибка обязательно произойдет, если в ваших исходных данных нет is_correct = 1.0 для определенного идентификатора. Если вы хотите, вы можете получить строку «NONE CORRECT», напечатанную обратно, если ни одна из них не верна.
Понятно, надо было отметить/включить это в фиктивный df. Я считаю, что Лиор теперь скорректировал свой ответ на основе вашего комментария, так что это подойдет для меня. Я бы проголосовал за ваши комментарии и ответил бы, но у меня недостаточно репутации.
Все в порядке, Экса, я просто рад узнать, что твоя проблема решена. Приятного обучения.
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, но он все равно не работает. Любая идея, почему это так? Я отредактировал вопрос в соответствии с этим.
нужно добавить iloc[0] в первый возвращаемый элемент. я обновил ответ
Второй список внутри списка списков говорит ['собака', 'собака', '0.0'], но для любой 'собаки' значение is_correct никогда не равно 1.0 Так это правильно?
Хороший улов, @amit. 0.0 — это строка, а bool('0.0') — True. Исправлено с помощью =='1.0'
.
Я не эксперт по пандам, но в последнее время я использовал его довольно часто. Вы можете сгруппировать свой фрейм данных с помощью следующего кода:
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"])
Надеюсь, поможет. Возможно, есть более векторизованный способ сделать это, но, как я уже говорил, я не эксперт.
Отлично, работает на манекене df! На моем df я получаю ошибку
IndexError: Cannot choose from an empty sequence
. Однако я дважды проверил, и у меня нет NaN в df. Любая идея, что происхождение может быть?