создайте столбец, который может подсчитывать дробь

#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)
 

Наконец, мы получим нужный вам фрейм данных:
введите описание изображения здесь