Эффективно применять вычисления к фрейму данных Pandas на основе условия?

#python #pandas #lambda #iteration #list-comprehension

#python #pandas #лямбда #итерация #понимание списка

Вопрос:

Я впервые использую Stack Overflow. Я совсем новичок в кодировании и Pandas, поэтому, пожалуйста, потерпите меня. Я практикую манипулирование данными, используя Python / Pandas вместо Excel, и я столкнулся со следующей проблемой…

Я пытаюсь стандартизировать значения для определенных столбцов по годам. Мой набор данных довольно мал, поэтому выбранный мной подход (показан ниже) работает хорошо, однако я совершенно уверен, что это не лучший способ выполнить эту задачу. Есть ли лучший способ сделать это с помощью понимания списка или применения функции к фрейму данных? (P.S. любые другие ресурсы, которые вы могли бы порекомендовать для изучения этих тем или для примеров, были бы очень признательны!)

Пример данных:

 IN: df = pd.DataFrame(data=[[2018,10,100,50], [2018,11,110,30], [2017,12,120,10], [2017, 15, 115, 40]], columns=['Year','c1','c2','c3'])
OUT:
   Year  c1   c2   c3
0  2018  10  100   50
1  2018  11  110   30
2  2017  12  120   10
3  2017  15  115   40
  

Пример вывода:

     Year    c1  c2  c3    c1_std      c2_std
0   2018    10  100 50  -0.707107   -0.707107
1   2018    11  110 30  0.707107    0.707107
2   2017    12  120 10  0.707107    0.707107
3   2017    15  115 40  -0.707107   -0.707107
  

Обратите внимание, что стандартизированный вывод предназначен только для 2 из 3 столбцов

Мой подход:

  1. Сначала я создал две таблицы. Один для средних значений по столбцу и году, а также один для стандартных отклонений по столбцу и году.

     standard_devs = pd.DataFrame(data=[],index=[2018,2017], columns=['c1', 'c2'])
    means = pd.DataFrame(data=[],index=[2018,2017], columns=['c1', 'c2'])  
    for y in [2018,2017]:
        for col in ['c1', 'c2']:
            standard_devs.loc[y,col] = df[df['Year']==y][col].std()
            means.loc[y,col] = df[df['Year']==y][col].mean()
      
  2. Я перебрал свой исходный фрейм данных и вычислил стандартизированные значения на основе соответствующего года и столбца.

     for i in list(df.index):
        for col in ['c1', 'c2']:
            year = df.loc[i,'Year']
            df.loc[i,col '_std'] = (df.loc[i,col]-means.loc[year, col])/standard_devs.loc[year, col]
      

Я читал ранее, что итерация по фрейму данных pandas является плохой практикой. Я знаю, что этот метод, вероятно, не может масштабироваться, поэтому мне было интересно, как я мог бы быть более эффективным с моим кодированием.

Спасибо вам всем!

Комментарии:

1. Пожалуйста, добавьте пример для вывода, т. Е. Какой результат вам нужен. Итерация должна быть последним средством в Pandas

2. Привет, gtomer, я добавил несколько примеров вывода.

Ответ №1:

Вы можете использовать groupby.transform здесь для вычисления std и mean . Это вычислит соответствующую метрику по группе и вернет ряд с одинаковой длиной оси df :

 for c in ['c1', 'c2']:
    stds = df.groupby('Year')[c].transform('std')
    means = df.groupby('Year')[c].transform('mean')
    df[f'{c}_std'] = (df[c] - means) / stds
  

Альтернативным подходом было бы временно установить ваш индекс на ваш ключ groupby:

 means = df.groupby('Year')[['c1', 'c2']].mean()
stds = df.groupby('Year')[['c1', 'c2']].std()

(df.join((((df.set_index('Year') - means) / stds))
         .reset_index(drop=True)
         .add_suffix('_std')))
  

[выход]

    Year  c1   c2  c3    c1_std    c2_std
0  2018  10  100  50 -0.707107 -0.707107
1  2018  11  110  30  0.707107  0.707107
2  2017  12  120  10 -0.707107  0.707107
3  2017  15  115  40  0.707107 -0.707107
  

Комментарии:

1. Привет, Крис, спасибо за твой ответ! Я должен был быть более четким в своем вопросе, но я не хочу стандартизировать каждый столбец в фрейме данных. В примере я стандартизировал только 2 из 3 столбцов. Кроме того, если бы я применил это к фрейму данных, в котором столбцы были нечисловыми, сработало бы это решение или оно потерпело бы неудачу, потому что длины результирующих фреймов данных means и stds отличались бы? Спасибо!

2. Произойдет сбой, если какой-либо из столбцов, к которым вы пытаетесь применить это, не является числовым.