У меня есть фрейм данных с двумя столбцами: хеш и результаты.
В хеш-столбце указан идентификатор задачи, он может повторяться несколько раз.
Столбец результатов содержит ответ пользователя на это задание. Ответы содержат конкретные строковые значения типа: «Да», «Нет», «Возможно», 404».
Моя задача — просчитать согласованность ответов пользователей.
Например, если на задачу с одним хешем 3 пользователя ответили одинаково, то согласованность равна 100%. Если 2 из 3 ответили одинаково, то 66,6. Если одно из 3, то 33,3%. Если все ответили по-разному, то 0.
Я пытался посчитать максимальное количество повторяющихся значений ответа для каждого хеша через «дублированный», но это не работает, когда повторяющихся значений нет.
Подскажите пожалуйста, какие функции можно использовать для решения этой проблемы.
дф, например:
df = pd.DataFrame({'hash': list('AAABBBCCCCDDD'),
'results': ['Yes', 'No', 'No',
'Yes', 'Yes', 'Yes',
'Perhaps', 'Yes', '404', 'Perhaps',
'Yes', 'No', 'Perhaps',
]
})
Да, именно количество этих наиболее частых значений для каждого хеша.
Моя вина, я изначально неправильно понял вопрос.
прочитайте уведомление: минимальный воспроизводимый пример
Поскольку вы не предоставляете никакого справочного кода, я создаю мини-скрипт Python для имитации вашего кода. Это то, что я использовал:
Сначала я создаю функцию, которая может принимать df и выполнять все операции.
def calculate_consistency(df):
Затем, прежде всего, я сгруппировал все записи по хешу и столбцам результатов:
df.groupby('hash')['result'].value_counts().unstack(fill_value=0)
Затем подсчитайте общее количество ответов для каждого хэша.
total_responses = grouped.sum(axis=1)
Чтобы найти максимальное количество для каждого хеша
max_counts = grouped.max(axis=1)
И, наконец, рассчитайте процент согласованности и верните согласованность.
consistency = (max_counts / total_responses) * 100
return consistency
Полный код с примером выглядит так:
import pandas as pd
def calculate_consistency(df):
grouped = df.groupby('hash')['result'].value_counts().unstack(fill_value=0)
total_responses = grouped.sum(axis=1)
max_counts = grouped.max(axis=1)
consistency = (max_counts / total_responses) * 100
return consistency
df = pd.DataFrame({'hash': ['A', 'A', 'A', 'B', 'B', 'C', 'C', 'C'], 'result': ['Yes', 'Yes', 'No', 'Yes', 'No', 'Perhaps', '404', 'Yes']})
result = calculate_consistency(df)
print(result)
Дайте мне знать, если это полезно для вас, удачи!
Спасибо большое, все работает и очень подробно. Остаётся одно, если все ответы разные, это тоже даёт 33%, как в этом случае сделать, чтобы выдавало 0?
В этом случае нам также следует позаботиться о unique_responses, поэтому после переменной max_counts мы должны добавить новую переменную, вызывающую unique_responses = (grouped > 0).sum(axis=1), чтобы вычислить количество уникальных ответов для каждого хеша, и, наконец, обновите переменную согласованности для этой новой концепции.
Не забудьте проголосовать за полезный вопрос и выбрать наиболее подходящий для вашего случая! Это было приятно
IIUC, вы можете построить перекрестную таблицу , получить (первое) наиболее распространенное значение и вычислить согласованность:
df = pd.DataFrame({'hash': list('AAABBBCCCCDDD'),
'results': ['Yes', 'No', 'No',
'Yes', 'Yes', 'Yes',
'Perhaps', 'Yes', '404', 'Perhaps',
'Yes', 'No', 'Perhaps',
]
})
# compute crosstab
tmp = pd.crosstab(df['hash'], df['results'])
# are all values different?
m = tmp.le(1).all(axis=1)
out = (pd.DataFrame({'top_answer': tmp.idxmax(axis=1).mask(m, '-'),
'consistency': tmp.max(axis=1)
.div(tmp.sum(axis=1))
.mask(m, 0)
})
.reset_index()
)
Выход:
hash top_answer consistency
0 A No 0.666667
1 B Yes 1.000000
2 C Perhaps 0.500000
3 D - 0.000000
Другой подход с groupby:
df = pd.DataFrame({'hash': list('AAABBBCCCCDDD'),
'results': ['Yes', 'No', 'No',
'Yes', 'Yes', 'Yes',
'Perhaps', 'Yes', 'Yes', 'Perhaps',
'Yes', 'No', 'Perhaps',
]
})
g = df.groupby('hash')['results']
# number of answers
na = g.size()
# number of unique answers
nu = g.nunique()
# most common answer
mc = g.agg(lambda x: x.mode().str.cat(sep='/'))
# count of most frequent
cnt = g.value_counts().groupby(level='hash').max()
# are all answers different?
m = nu == na
out = (pd.DataFrame({'top_answer': mc.mask(m, '-'),
'consistency': (nu/na).mask(m, 0),
'nb_answers': na,
'nb_unique_answers': nu,
'count_top': cnt,
})
.reset_index()
)
Вариант вычисления наиболее распространенного ответа:
# count of most frequent
tmp = g.value_counts().reset_index(1)
cnt = tmp.groupby(level=0)['count'].max()
# most common answer
mc = (tmp.loc[tmp['count'].eq(cnt),'results']
.groupby(level=0).agg('/'.join)
)
Обратите внимание, что в случае ничьей это объединит наиболее распространенные ответы, если вы хотите использовать только одно (случайное) mc = g.agg(lambda x: x.mode()[0])
.
Выход:
hash top_answer consistency nb_answers nb_unique_answers count_top
0 A No 0.666667 3 2 2
1 B Yes 0.333333 3 1 3
2 C Perhaps/Yes 0.500000 4 2 2
3 D - 0.000000 3 3 1
Это тоже отлично работает, большое спасибо. Только если все ответы разные, мне нужно получить 0, подскажите плс как это можно сделать наиболее рационально
@Дмитрий, посмотрите, соответствует ли вам обновление, но, пожалуйста, отредактируйте свой вопрос, чтобы добавить минимально воспроизводимый пример с ожидаемым результатом (вы можете повторно использовать мой пример, если хотите)
Он дает номер каждого ответа. Как получить только то количество ответов, которые встречаются чаще всего?