#python #pandas
Вопрос:
У меня есть фрейм данных, аналогичный приведенному ниже:
name x y
Sam 1 NA
John 1 NA
Lilly 0 1
Lilly 1 1
John NA 0
Sam 1 NA
Из этого фрейма данных я надеюсь создать два новых столбца с именами percentage_0 и percentage_1
Для каждого имени я вычисляю процент 1 и процент 0. Например. У Лилли всего 4 значения 0, 1, 1, 1, возврат должен быть percentage_0: 0,25 и percentage 1: 0,75
Окончательное возвращение должно выглядеть так
name percentage_0 percentage 1
Sam 0 1
John 0.5 0.5
lilly 0.25 0.75
мой код таков
df['percentage_0'] = df[df['x'] == 1].count()/len(df['name'])
но этот код не работает
Ответ №1:
Попробуйте с melt
и crosstab
:
s=df.melt('name').dropna()
out = (pd.crosstab(s['name'], s['value'], normalize='index')
.add_prefix('percentage_')
)
Выход:
value percentage_0.0 percentage_1.0
name
John 0.50 0.50
Lilly 0.25 0.75
Sam 0.00 1.00
Обновление: melt
может быть медленным, попробуйте с groupby:
groups = df.groupby('name')
out = (groups['x'].value_counts().rename_axis(index=('name',None))
.add(groups['y'].value_counts().rename_axis(index=('name',None)), fill_value=0)
.unstack(fill_value=0)
)
out.div(out.sum(1), axis=0)
Комментарии:
1. не могли бы вы рассказать мне, как обращаться с «ценностью»? У меня есть два столбца значений, один — «x», а другой — «y».
2. Есть ли какой-нибудь более быстрый способ запустить это? размер данных большой, и для запуска потребовалась вечность
3. Есть ли в ваших данных другие столбцы? Это не должно быть так медленно, всего с 3 столбцами.
4. Другого столбца нет, только эти три, но в нем 206605310 строк. Я запускал его в течение 6 минут, но все равно безрезультатно
5. @totolow посмотрите, поможет ли обновленный ответ.
Ответ №2:
Предполагая NA
, что это какая-то форма np.nan
(которую было бы хорошо стандартизировать в любом случае):
df.set_index("name", inplace=True)
df = df.stack().reset_index(drop=True, level=1).reset_index()
df = (
df.groupby("name")[0]
.value_counts(normalize=True)
.unstack(level=1)
.fillna(0)
)
df.columns = map(lambda x: f"percentage_{int(x)}", df.columns)
ВОЗВРАТ:
percentage_0 percentage_1
name
John 0.50 0.50
Lilly 0.25 0.75
Sam 0.00 1.00
Ответ №3:
Давайте сначала построим фрейм данных в вопросе:
import numpy as np
import pandas as pd
name = ['Sam', 'John', 'Lilly', 'Lilly', 'John', 'Sam']
x = [1, 1, 0, 1, np.nan, 1]
y = [np.nan, np.nan, 1, 1, 0, np.nan]
df = pd.DataFrame({'name':name, 'x':x, 'y':y})
df
Получите фрейм данных в вопросе следующим образом:
Теперь давайте получим нужный вам фрейм данных, чтобы быстро получить количество 0 и 1, нам лучше преобразовать его в массив numpy с функцией «значения».:
d = {'name':list(set(df['name'])), 'percentage_0':[], 'percentage_1':[]}
for e in d['name']:
value = df[df['name'] == e].values
value1 = np.count_nonzero(value == 1)
value0 = np.count_nonzero(value == 0)
d['percentage_0'].append(value0/(value0 value1))
d['percentage_1'].append(value1/(value0 value1))
pd.DataFrame(d)