Как изменить форму фрейма данных или выполнить UnPivot на основе заголовков, а затем вставить два столбца

#python #python-3.x #pivot

#python #python-3.x #сводная

Вопрос:

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

  ACCEPTANCES_EXECUTED_FOR_ACCT____OUT    ACCUMULATED_OTH_COMPREHENSIVE_INCOME    ALLL_AMT    AUDIT_INDICATOR     AVAILABLE_FOR_SALE_SECURITIES   COMMON_STOCK    file 
 $-                                      $-                                      $979.00     $1.00               $-                              $1,200.00       FFIEC CDR Call Schedule RC0 03312001.txt
 $-                                      $93.00                                  $127.00     $4.00               $8,546.00                       $120.00         FFIEC CDR Call Schedule RC0 03312001.txt
 $-                                      $246.00                                 $278.00     $1.00               $27,398.00                      $-              FFIEC CDR Call Schedule RC0 03312002.txt
 $-                                      $19.00                                  $130.00     $4.00               $4,047.00                       $25.00          FFIEC CDR Call Schedule RC0 03312002.txt
 $-                                      $125.00                                 $1,188.00   $1.00               $21,265.00                      $596.00         FFIEC CDR Call Schedule RC0 03312002.txt
 $-                                      $-                                      $164.00     $4.00               $-                              $60.00          FFIEC CDR Call Schedule RC0 03312002.txt
 $-                                      $800.00                                 $2,115.00   $1.00               $55,699.00                      $5,400.00       FFIEC CDR Call Schedule RC0 03312003.txt
 $-                                      $199.00                                 $2,372.00   $2.00               $32,306.00                      $19.00          FFIEC CDR Call Schedule RC0 03312003.txt
 $-                                      $174.00                                 $1,114.00   $5.00               $18,296.00                      $1,600.00       FFIEC CDR Call Schedule RC0 03312004.txt
 $-                                      $31.00                                  $323.00     $5.00               $2,997.00                       $240.00         FFIEC CDR Call Schedule RC0 03312004.txt
 

Как я могу повернуть данные так, чтобы они выглядели так?

 Code     Schedule            Line Item                                  Q12001      Q22002      Q32003       Q42004
RC0      BalanceSheet        ACCEPTANCES_EXECUTED_FOR_ACCT____OUT       $-          $-          $-           $-   
RC0      BalanceSheet        ACCUMULATED_OTH_COMPREHENSIVE_INCOME       $93.00      390         $999.00      $205.00 
RC0      BalanceSheet        ALLL_AMT                                   $1,060.00   $1,760.00   $4,487.00    $1,437.00 
RC0      BalanceSheet        AUDIT_INDICATOR                            $5.00       $10.00      $3.00        $10.00 
RC0      BalanceSheet        AVAILABLE_FOR_SALE_SECURITIES              $8,546.00   $52,710.00  $88,050.00   $21,293.00 
RC0      BalanceSheet        COMMON_STOCK                               $1,320.00   $681.00     $5,419.00    $1,840.00 
 

Я не вижу этого, это стандартное упражнение по сводке, потому что мне нужно разобрать имя файла на кварталы и годы, так что это: ‘Расписание вызовов FFIEC CDR RC0 03312001.txt ‘

Становится следующим: ‘Q12001’

  1. Я хотел бы добавить «Элемент строки» в качестве заголовка
  2. Я бы хотел, чтобы в самом первом столбце был заголовок ‘Code’, а под ним должно быть имя файла, которое является ‘RC0’.
  3. Я хотел бы добавить

Это выглядит примерно так…

 output = df_append.pivot(index='headers', columns='file')
print(output)
 

Но, конечно, нет столбца с именем «заголовки», и я не могу понять, как разобрать файл на кварталы и годы. В этом фрейме данных более 100 полей, а «файл» насчитывает почти 20 лет, разделенных на кварталы и годы. Возможно ли это вообще ?!

Ответ №1:

Хотя это немного сложно, я смог решить эту проблему.

Шаги:

1. Настройте фрейм данных

2. Очистите данные, удалив $, запятую и тире. Затем преобразуйте данные в значения с плавающей запятой

3. Извлеките код (RC0, RC1 …) и дату (MMDDYYYY) из filename

4. Создайте квартальный период с даты

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

6. Транспонируйте результат для создания в запрошенном формате

7. Сделайте квартальный период заголовком столбца и удалите квартальную строку

8. Переименуйте имя оси в строку в соответствии с вашим запросом

9. Добавьте расписание в качестве имени столбца в соответствии с вашим запросом

10. Распечатайте окончательный фрейм данных

Вот код для этого.

 import pandas as pd
import numpy as np

#Dataframe setup activities

c = ['ACCEPTANCES_EXECUTED_FOR_ACCT____OUT',
     'ACCUMULATED_OTH_COMPREHENSIVE_INCOME',
     'ALLL_AMT',
     'AUDIT_INDICATOR',
     'AVAILABLE_FOR_SALE_SECURITIES',
     'COMMON_STOCK',
     'file']
d = [
['$-','$-'     ,'$979.00'  ,'$1.00','$-'        ,'$1,200.00','FFIEC CDR Call Schedule RC0 03312001.txt'],
['$-','$93.00' ,'$127.00'  ,'$4.00','$8,546.00' ,'$120.00'  ,'FFIEC CDR Call Schedule RC0 03312001.txt'],
['$-','$246.00','$278.00'  ,'$1.00','$27,398.00','$-'       ,'FFIEC CDR Call Schedule RC0 03312002.txt'],
['$-','$19.00' ,'$130.00'  ,'$4.00','$4,047.00' ,'$25.00'   ,'FFIEC CDR Call Schedule RC0 03312002.txt'],
['$-','$125.00','$1,188.00','$1.00','$21,265.00','$596.00'  ,'FFIEC CDR Call Schedule RC0 03312002.txt'],
['$-','$-'     ,'$164.00'  ,'$4.00','$-'        ,'$60.00'   ,'FFIEC CDR Call Schedule RC1 03312002.txt'],
['$-','$800.00','$2,115.00','$1.00','$55,699.00','$5,400.00','FFIEC CDR Call Schedule RC1 03312003.txt'],
['$-','$199.00','$2,372.00','$2.00','$32,306.00','$19.00'   ,'FFIEC CDR Call Schedule RC0 03312003.txt'],
['$-','$174.00','$1,114.00','$5.00','$18,296.00','$1,600.00','FFIEC CDR Call Schedule RC1 03312004.txt'],
['$-','$31.00' ,'$323.00'  ,'$5.00','$2,997.00' ,'$240.00'  ,'FFIEC CDR Call Schedule RC0 03312004.txt']]

df = pd.DataFrame(d,columns=c)

#Dataframe cleanup activities. Remove $ sign, comma and dash to enable computing

df[df.columns[:6]] = df[df.columns[:6]].apply(lambda x: x.str.replace('[$,]','',regex=True).replace('-','0',regex=True)).astype(np.float64)

#Extract code from the filename

df['code'] = df['file'].str[24:27]

#Extract Date (MMDDYYYY) from file name

df['year'] = pd.to_datetime(df['file'].str[28:36],format='%m%d%Y').dt.strftime('%m/%d/%Y')

#Create a Quarterly Period from the date

df['qyear'] = pd.PeriodIndex(df['year'], freq='Q')

#Calculate the sum based on Quarteryly values using Groupby
#Transpose to create the dataframe in the format you wanted. Store it into df1

df1 = df.groupby(['code','qyear']).agg({'ACCEPTANCES_EXECUTED_FOR_ACCT____OUT':'sum',
                  'ACCUMULATED_OTH_COMPREHENSIVE_INCOME':'sum',
                  'ALLL_AMT':'sum',
                                   'AUDIT_INDICATOR':'sum',
                                   'AVAILABLE_FOR_SALE_SECURITIES':'sum',
                                   'COMMON_STOCK':'sum'}).reset_index().T

#Make Quarterly Period as the column header and delete the quarterly row
df1.columns = df1.loc['qyear']
df1.drop(['qyear'],axis=0,inplace=True)

#Rename the axis name to Line Item as per your request
df1.rename_axis('Line Item',axis="columns",inplace=True)

#Add Schedule as the column name as per your request
df1['Schedule'] = 'BalanceSheet'

#You now have the final dataframe as per your request
print (df1)
 

Обратите внимание, что если filename имеет значения больше 1 code (RC0, то для каждого RC-кода настраиваются отдельные наборы квартальных периодов (в виде столбцов). Из-за этого мы не можем обобщить код на RC0. Кроме того, у меня возникают некоторые трудности при вычислении значений позиций строк для кода RC и добавлении их в виде отдельных строк. Глядя на то, как организованы данные, лучше всего, чтобы RC0 и RC1 с квартальными периодами отображались в отдельных столбцах, а не дублировали позиции для каждой группы RC.

Окончательный фрейм данных выглядит следующим образом (обратите внимание, что в этом у меня есть RC0 и RC1):

 Line Item                            2001Q1 2002Q1 2003Q1 2004Q1 2002Q1  
code                                    RC0    RC0    RC0    RC0    RC1   
ACCEPTANCES_EXECUTED_FOR_ACCT____OUT      0      0      0      0      0   
ACCUMULATED_OTH_COMPREHENSIVE_INCOME     93    390    199     31      0   
ALLL_AMT                               1106   1596   2372    323    164   
AUDIT_INDICATOR                           5      6      2      5      4   
AVAILABLE_FOR_SALE_SECURITIES          8546  52710  32306   2997      0   
COMMON_STOCK                           1320    621     19    240     60   

Line Item                            2003Q1 2004Q1      Schedule  
code                                    RC1    RC1  BalanceSheet  
ACCEPTANCES_EXECUTED_FOR_ACCT____OUT      0      0  BalanceSheet  
ACCUMULATED_OTH_COMPREHENSIVE_INCOME    800    174  BalanceSheet  
ALLL_AMT                               2115   1114  BalanceSheet  
AUDIT_INDICATOR                           1      5  BalanceSheet  
AVAILABLE_FOR_SALE_SECURITIES         55699  18296  BalanceSheet  
COMMON_STOCK                           5400   1600  BalanceSheet  
 

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

Вместо преобразования фрейма данных я делаю это чуть позже. Это позволяет мне добавлять знак $ к значениям.

df1 =

 df.groupby(['code','qyear']).agg({'ACCEPTANCES_EXECUTED_FOR_ACCT____OUT':'sum',
                  'ACCUMULATED_OTH_COMPREHENSIVE_INCOME':'sum',
                  'ALLL_AMT':'sum',
                                   'AUDIT_INDICATOR':'sum',
                                   'AVAILABLE_FOR_SALE_SECURITIES':'sum',
                                   'COMMON_STOCK':'sum'}).reset_index()
cols = df1.columns[2:]
df1.loc[:, cols] = df1[cols].astype(float).applymap('${:,.2f}'.format)
df1 = df1.T
df1.columns = df1.loc['qyear']
 

Если я преобразую данные, то RC0/1… также появится, и я не могу добавить значение в размере $. Так что делай это до того, как я трансформируюсь.

Результат выглядит следующим образом:

 Line Item                                2001Q1      2002Q1      2003Q1  
code                                        RC0         RC0         RC0   
ACCEPTANCES_EXECUTED_FOR_ACCT____OUT      $0.00       $0.00       $0.00   
ACCUMULATED_OTH_COMPREHENSIVE_INCOME     $93.00     $390.00     $199.00   
ALLL_AMT                              $1,106.00   $1,596.00   $2,372.00   
AUDIT_INDICATOR                           $5.00       $6.00       $2.00   
AVAILABLE_FOR_SALE_SECURITIES         $8,546.00  $52,710.00  $32,306.00   
COMMON_STOCK                          $1,320.00     $621.00      $19.00   

Line Item                                2004Q1   2002Q1      2003Q1  
code                                        RC0      RC1         RC1   
ACCEPTANCES_EXECUTED_FOR_ACCT____OUT      $0.00    $0.00       $0.00   
ACCUMULATED_OTH_COMPREHENSIVE_INCOME     $31.00    $0.00     $800.00   
ALLL_AMT                                $323.00  $164.00   $2,115.00   
AUDIT_INDICATOR                           $5.00    $4.00       $1.00   
AVAILABLE_FOR_SALE_SECURITIES         $2,997.00    $0.00  $55,699.00   
COMMON_STOCK                            $240.00   $60.00   $5,400.00   

Line Item                                 2004Q1      Schedule  
code                                         RC1  BalanceSheet  
ACCEPTANCES_EXECUTED_FOR_ACCT____OUT       $0.00  BalanceSheet  
ACCUMULATED_OTH_COMPREHENSIVE_INCOME     $174.00  BalanceSheet  
ALLL_AMT                               $1,114.00  BalanceSheet  
AUDIT_INDICATOR                            $5.00  BalanceSheet  
AVAILABLE_FOR_SALE_SECURITIES         $18,296.00  BalanceSheet  
COMMON_STOCK                           $1,600.00  BalanceSheet  
 

Если вы хотите заменить все на $0.00 , $- то вы можете сделать:

 df1.replace(to_replace = '$0.00', value = '$-', inplace = True)
 

Если у вас есть разные столбцы и вы хотите объединить их все, то сделайте это.

Предполагая, что последний столбец file равен, и вы хотите объединить все столбцы от индекса 0 до предпоследнего, вы можете сделать это:

 cagg = {cx:'sum' for cx in df.columns[:-1]}
df1 = df.groupby(['code','qyear']).agg(cagg).reset_index()
 

Поскольку вы собираетесь добавить 3 столбца ближе к концу:

 df['code'] = df['file'].str[24:27]
df['year'] = pd.to_datetime(df['file'].str[28:36],format='%m%d%Y').dt.strftime('%m/%d/%Y')
df['qyear'] = pd.PeriodIndex(df['year'], freq='Q')
 

Вы можете изменить код следующим образом [:-4], чтобы исключить столбцы file code year qyear:

 df = pd.DataFrame(d,columns=c)
df[df.columns[:6]] = df[df.columns[:6]].apply(lambda x: x.str.replace('[$,]','',regex=True).replace('-','0',regex=True)).astype(np.float64)
df['code'] = df['file'].str[24:27]
df['year'] = pd.to_datetime(df['file'].str[28:36],format='%m%d%Y').dt.strftime('%m/%d/%Y')
df['qyear'] = pd.PeriodIndex(df['year'], freq='Q')
cagg = {cx:'sum' for cx in df.columns[:-4]}
df1 = df.groupby(['code','qyear']).agg(cagg).reset_index()
 

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

1. Да, да! Это довольно сексуально! Ваша версия определенно работает. Мне просто нужно адаптировать это к моим фактическим данным. Большое спасибо!!

2. Быстрый вопрос: вместо этого… Акцепты_выполняются_для_Счет____из’:’сумма’, ‘ACCUMULATED_OTH_COMPREHENSIVE_INCOME’:’сумма’, ‘ALLL_AMT’:’сумма’, ‘AUDIT_INDICATOR’:’сумма’, ‘AVAILABLE_FOR_SALE_SECURITIES’:’сумма’, ‘COMMON_STOCK’ …я могу просто использовать переменную… вот так? c = df_append.столбцы

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

4. да, ты можешь. Я добавил код, чтобы вы могли его увидеть

5. О, я нашел обходной путь! Это то, что я в конечном итоге использовал. grouped_df = df.groupby([‘code’,’qyear’]) grouped_and_summed = grouped_df.sum() grouped_and_summed = grouped_and_summed.reset_index() . T Еще раз спасибо!!!