Создайте новый фрейм данных, применив функцию к столбцам другого фрейма данных. - PullRequest
0 голосов
/ 13 февраля 2019

Я пытаюсь узнать больше о методе apply в python и спрашиваю себя, как написать следующий код, используя apply:

У меня есть датафрейм df, подобный следующему:

  A B C D E points
0 0 0 0 1 43 94
1 0 0 1 1 55 62
2 1 1 0 1 21 84
3 1 0 1 0 13 20

Кроме того, у меня есть функция, подобная следующей, которая выполняет свою работу:

def f1(df):
  df_means = pd.DataFrame(columns = ['Mean_Points'])
  for columnname in df.columns:
    if len(df[df[columnname] == 1]) > 1:
      df_means.loc[columnname] = [df[df[columnname] == 1]['points'].mean()]
  return df_means

Так что вывод f1 равен

  'Mean_Points'
A      52
C      41
D      80

, и это совершенно нормально.Но мне интересно, есть ли возможность (я уверен, что есть) получить тот же результат с помощью метода apply.Я пробовал:

df_means = pd.DataFrame(columns = ['Mean_Points'])
cols = [col for col in df.columns if len(df[df[col] == 1]) > 1]
df_means.loc[cols] = df[cols].apply(lambda x: df[df[x] == 1]['points'].mean(), axis = 1)

или подобное:

df_means = pd.DataFrame(columns = ['Mean_Points'])
df.columns.apply(lambda x: df_means.loc[x] = [df[df[x] == 1]['points'].mean()] if len(df[df[x] == 1]) > 1 else None)

и еще 2,3, но ничего не помогло ... Надеюсь, кто-нибудь может мне здесь помочь?!

Ответы [ 3 ]

0 голосов
/ 13 февраля 2019

pd.DataFrame.dot

#                      filters s to be just those
#                      things greater than 1
#                      v
s = df.eq(1).sum().loc[lambda x: x > 1]
df.loc[:, s.index].T.dot(df.points).div(s)

A    52.0
C    41.0
D    80.0
dtype: float64

Подход с одним вкладышем

При этом удаляется зерно, но, вероятно, выполняется больше вычислений, чем необходимо.

df.T.dot(df.points).div(df.sum())[df.eq(1).sum().gt(1)]

A    52.0
C    41.0
D    80.0
dtype: float64
0 голосов
/ 13 февраля 2019

Вот еще один способ сделать это, а не просто панд , как другие показали.

cols = ['A', 'B', 'C', 'D']

def consolidate(series):
    cond = series > 0
    points = df.loc[cond, 'points']
    if len(points) > 1:
        return series.name, points.mean()
    else:
        return series.name, np.nan

df1 = pd.DataFrame([consolidate(df[col]) for col in cols], columns=['name', 'mean_points'])


print(df1)


  name  mean_points
0    A         52.0
1    B          NaN
2    C         41.0
3    D         80.0

Если NaN не требуется, то

df1.dropna()

  name  mean_points
0    A         52.0
2    C         41.0
3    D         80.0

И используя apply

df[cols].apply(consolidate,result_type='expand')
        .T.dropna()
        .reset_index()
        .drop('index', axis=1)

0  A  52
1  C  41
2  D  80
0 голосов
/ 13 февраля 2019

В общем, вы должны попытаться выяснить, можете ли вы избегать использования .apply(axis=1).

В этом случае вы можете обойтись с DataFrame.mulitply(), заменив 0 на np.NaN, чтобы оно не учитывалось в среднем.

import numpy as np

s = df.replace(0, np.NaN).multiply(df.points, axis=0).mean()
#A           52.0
#B           84.0
#C           41.0
#D           80.0
#E         2369.0
#points    5034.0
#dtype: float64

Теперь мы будемдобавьте ваше условие, чтобы рассматривать только столбцы с несколькими экземплярами 1 и подмножество столбцов с .reindex

m = df.eq(1).sum().gt(1)
s = s.reindex(m[m].index)

Выходными данными s:

A      52.0
C      41.0
D      80.0
dtype: float64
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...