#python #pandas
#python #pandas
Вопрос:
Новичок здесь…
У меня есть фрейм данных с именем ‘yes_no’, структурированный следующим образом (но в нем около 50 тыс. записей):
Date Yes/No
0 2020-10-27 No
1 2020-10-27 No
2 2020-10-26 Yes
3 2020-10-26 Yes
4 2020-10-26 No
5 2020-10-25 No
6 2020-10-25 Yes
7 2020-10-25 No
8 2020-10-24 Yes
9 2020-10-24 Yes
Мне нужно подсчитать количество yes и количество nos для каждой даты и вычислить соотношение, чтобы в итоге получилось что-то вроде этого:
Date Yes No Percentage
0 2020-10-27 1142 120 0.904913
1 2020-10-26 4112 388 0.913778
2 2020-10-25 1055 68 0.939448
3 2020-10-24 1012 86 0.921676
4 2020-10-23 1476 163 0.900549
5 2020-10-22 1633 182 0.899725
6 2020-10-21 1773 237 0.882090
7 2020-10-20 2332 246 0.904577
8 2020-10-19 2868 326 0.897934
9 2020-10-18 892 107 0.892893
10 2020-10-17 992 110 0.900181
11 2020-10-16 2106 207 0.910506
12 2020-10-15 5628 632 0.899042
13 2020-10-14 9304 937 0.908505
14 2020-10-13 8129 881 0.902220
Я заставил его работать со следующим кодом, просмотрев словарь, но он невероятно длинный:
by_date = {}
for date in yes_no['Date']:
by_date[date] = yes_no.loc[yes_no['Date'] == date]
for date in by_date:
by_date[date] = by_date[date]['Yes/No'].value_counts()
for date in by_date:
if 'No' not in by_date[date]:
by_date[date]['No'] = 0
for date in by_date:
if 'Yes' not in by_date[date]:
by_date[date]['Yes'] = 0
for date in by_date:
by_date[date] = [by_date[date]['Yes'], by_date[date]['No'], (by_date[date]['Yes']/(by_date[date]['Yes'] by_date[date]['No']))]
df_yes = pd.DataFrame(list(by_date.values()),columns = ['Yes', 'No', 'Percentage'])
df_yes['Date'] = list(by_date.keys())
df_yes = df_yes[['Date', 'Yes', 'No', 'Percentage']]
Он отлично работал с меньшим фреймом данных (1-2 КБ), но для обработки этого фрагмента кода с 50 тыс. записей требуется вечность:
for date in yes_no['Date']:
by_date[date] = yes_no.loc[yes_no['Date'] == date]
Должен быть лучший способ сделать это!
Ответ №1:
Вы можете сделать это гораздо эффективнее, используя векторизованные операции (без явного цикла python). Это означает, что все наши операции выполняются базовыми функциями C / C для огромного ускорения.
out = (df.groupby("Date")["Yes/No"]
.value_counts()
.unstack(fill_value=0)
.rename_axis(columns=None)
.eval("percentage = Yes / (Yes No)")
)
print(out)
No Yes percentage
Date
2020-10-24 0 2 1.000000
2020-10-25 2 1 0.333333
2020-10-26 1 2 0.666667
2020-10-27 2 0 0.000000
Шаги:
df.groupby("Date")["Yes/No"]
: сгруппируйте наш фрейм данных по «Дате» и выберите столбец «Да / Нет» из этих группировок.value_counts()
: Получить количество каждого «да» и «нет» в этом столбце для каждой из этих группировок..unstack(fill_value=0)
: Теперь, когда у нас есть наши подсчеты, мы вносим «Да» и «Нет» в их собственные столбцы..rename_axis(columns=None)
: У нас забавно выглядящее имя индекса столбца, мне лично это не нравится, поэтому я избавляюсь от него..eval("percentage = Yes / (Yes No)")
: Создайте новый столбец с именем percentage и присвоите ему значения всех значений «Да», разделенных на общее количество ответов («Да» «Нет»
Комментарии:
1. Спасибо — это решило проблему аккуратно и почти мгновенно.
Ответ №2:
# groupby date and yes/no columns and get the size
# then pivot
new_df = df.groupby(['Date', 'Yes/No'], as_index=False).size().pivot('Date', 'Yes/No', 'size').replace(np.nan, 0)
# divide the yes column by the size of each group
new_df['percent_yes'] = new_df['Yes'] / new_df.sum(1)
print(new_df)
Yes/No No Yes percent_yes
Date
2020-10-24 0.0 2.0 1.000000
2020-10-25 2.0 1.0 0.333333
2020-10-26 1.0 2.0 0.666667
2020-10-27 2.0 0.0 0.000000
Комментарии:
1. использовать
unstack(fill_value=0)
вместо pivot2. Вам нужно будет удалить
as_index=False
из вызова groupby, чтобы использоватьunstack(...)
метод
Ответ №3:
Вам следует обратить внимание на одноразовое кодирование. pandas использует pd.get_dummies
Мое решение было бы:
df_new = pd.get_dummies(yes_no, columns=["Yes/No"]).groupby("Date").sum().rename(columns={"Yes/No_No":"No", "Yes/No_Yes":"Yes"}
И тогда вы можете легко рассчитать процент.
Ответ №4:
Существует очень простой способ сделать это, возможно, доступны более элегантные способы:
import pandas as pd
df = pd.DataFrame({'Yes_no': ['yes','no','yes', 'yes', 'no','yes','no','yes', 'yes', 'no','yes','no','yes', 'yes', 'no','yes','no','yes', 'yes', 'no'],
'Dates': ['2019-07-01','2019-07-01','2019-07-01', '2019-07-03', '2019-07-03','2019-07-03','2019-07-07','2019-07-07', '2019-07-07', '2019-07-07','2019-07-07','2019-07-07','2019-07-07', '2019-07-07', '2019-07-07','2019-07-07','2019-07-07','2019-07-07', '2019-07-07', '2019-07-07']})
dff = df.groupby(['Yes_no','Dates'])['Yes_no'].count()
dff.unstack().T
чтобы создать дополнительный столбец с пропорциями, просто определите новый столбец
dff['prop']=dff['no']/dff['yes']