Прочитать n таблиц в CSV-файле для разделения pandas DataFrames - PullRequest
1 голос
/ 13 января 2020

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

Я хотел бы прочитать каждую таблицу в отдельный pandas DataFrame для анализа. Вот подмножество данных:

Balance Sheet               
Report Date               12/31/2001    12/31/2000  12/31/1999  12/31/1998
Cash & cash equivalents   2279861       522995      418819      378511
Short-term investments    -             -           -            -
Accounts & other receivables    71283   138070      73448       88799
Inventories of parts...   70561          80564        65152     50035

Income Statement                
Report Date               12/31/2001    12/31/2000  12/31/1999  12/31/1998
Passenger revenues        5378702       5467965     4499360     3963781
Freight revenues          91270         110742      102990      98500
Charter & other           -              -           -           -
Special revenue adjustment  -            -           -           -

Statement of Retained Earnings              
Report Date              12/31/2001    12/31/2000   12/31/1999  12/31/1998
Previous ret earn...     2902007       2385854      2044975     1632115
Cumulative effect of..    -              -            -          -
Three-for-two stock split   117885  -   78076   -
Issuance of common..     52753           75952       45134       10184

Каждая из таблиц состоит из 17 столбцов, первый из которых содержит описание отдельной позиции, но различное количество строк, т. Е. Баланс составляет 100 строк, в то время как утверждение о потоках ca sh равно 65

Что я сделал

import pandas as pd
import numpy as np

# Lines that separate the various financial statements
lines_to_skip = [0, 102, 103, 158, 159, 169, 170]

with open('LUV.csv', 'r') as file:
    fin_statements = pd.read_csv(file, skiprows=lines_to_skip)

balance_sheet = fin_statements[0:100]

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

Я ищу комментарии и конструктивную критику для создания фрейма данных для каждой соответствующей таблицы в лучшем стиле Pythoni c и наилучшем практики.

Ответы [ 2 ]

0 голосов
/ 13 января 2020

Что вы хотите сделать, если далеко за пределами того, что может read_csv. Если факт, что вы вводите структуру файла, может быть смоделирован как:

REPEAT:
    Dataframe name
    Header line
    REPEAT:
        Data line
   BLANK LINE OR END OF FILE

ИМХО, самый простой способ - это анализ строки вручную строка за строкой, подача временного файла csv для каждого кадра данных, затем загрузка данных. Код может быть:

df = {}        # dictionary of dataframes

def process(tmp, df_name):
'''Process the temporary file corresponding to one dataframe'''                
    # print("Process", df_name, tmp.name)  # uncomment for debugging
    if tmp is not None:
        tmp.close()
        df[df_name] = pd.read_csv(tmp.name)
        os.remove(tmp.name)                # do not forget to remove the temp file

with open('LUV.csv') as file:
    df_name = "NONAME"                     # should never be in resulting dict...
    tmp = None
    for line in file:
        # print(line)                      # uncomment for debugging
        if len(line.strip()) == 0:         # close temp file on empty line
            process(tmp, df_name)          # and process it
            tmp = None
        elif tmp is None:                  # a new part: store the name
            df_name = line.strip()
            state = 1
            tmp = tempfile.NamedTemporaryFile("w", delete=False)
        else:
            tmp.write(line)                # just feed the temp file

    # process the last part if no empty line was present...
    process(tmp, df_name)

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

Возможное улучшение будет для первоначального анализа частей с помощью модуля csv (может анализировать поток, пока pandas хочет файлы). Недостатком является то, что модуль csv анализирует только строки, и вы теряете автоматические преобразования c в числа pandas. Мое мнение таково, что оно того стоит, только если файл большой и полную операцию придется повторить.

0 голосов
/ 13 января 2020

Вот мое решение: я предполагаю, что каждый отчет начинается с индикатора («Бухгалтерский баланс», «Отчет о прибылях и убытках», «Отчет о нераспределенной прибыли»), мы можем разделить таблицу на основе этого, чтобы получить отдельные кадры данных. Это предпосылка, на которой основан следующий код. дайте мне знать, если это ошибочное предположение.

import pandas as pd
import numpy as np

#i copied your data above and created a csv with it

df = pd.read_csv('csvtable_stackoverflow',header=None)

        0
0   Balance Sheet
1   Report Date 12/31/2001 12/31/...
2   Cash & cash equivalents 2279861 522995...
3   Short-term investments - - ...
4   Accounts & other receivables 71283 138070...
5   Inventories of parts... 70561 80564...
6   Income Statement
7   Report Date 12/31/2001 12/31/...
8   Passenger revenues 5378702 546796...
9   Freight revenues 91270 110742...
10  Charter & other - - ...
11  Special revenue adjustment - - ...
12  Statement of Retained Earnings
13  Report Date 12/31/2001 12/31/2...
14  Previous ret earn... 2902007 2385854...
15  Cumulative effect of.. - - ...
16  Three-for-two stock split 117885 - 78076 -
17  Issuance of common.. 52753 75952...

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

https://docs.scipy.org/doc/numpy/reference/generated/numpy.select.html

bal_sheet = df[0].str.strip()=='Balance Sheet'
income_stmt = df[0].str.strip()=='Income Statement'
cash_flow_sheet = df[0].str.strip()=='Statement of Retained Earnings'
condlist = [bal_sheet, income_stmt, cash_flow_sheet]
choicelist = ['Balance Sheet', 'Income Statement', 'Statement of 
                                                   Retained Earnings']

Следующий код ниже создает столбец с указанием типа листа, преобразует '0' в ноль и затем заполняет

df = (df.assign(sheet_type = np.select(condlist,choicelist))
      .assign(sheet_type = lambda x: x.sheet_type.replace('0',np.nan))
      .fillna(method='ffill')
      )

Последний шаг - вытянуть Из отдельных кадров данных

df_bal_sheet = df.copy().query('sheet_type=="Balance Sheet"')
df_income_sheet = df.copy().query('sheet_type=="Income Statement"')
df_cash_flow = df.copy().query('sheet_type=="Statement of Retained Earnings"')

df_bal_sheet :     
         0                                            sheet_type
0   Balance Sheet                                    Balance Sheet
1   Report Date 12/31/2001 12/31/...                 Balance Sheet
2   Cash & cash equivalents 2279861 522995...        Balance Sheet
3   Short-term investments - - ...                   Balance Sheet
4   Accounts & other receivables 71283 138070...     Balance Sheet
5   Inventories of parts... 70561 80564...           Balance Sheet

df_income_sheet : 
           0                                     sheet_type
6   Income Statement                           Income Statement
7   Report Date 12/31/2001 12/31/...           Income Statement
8   Passenger revenues 5378702 546796...       Income Statement
9   Freight revenues 91270 110742...           Income Statement
10  Charter & other - - ...                    Income Statement
11  Special revenue adjustment - - ...         Income Statement

df_cash_flow:
              0                                         sheet_type
12  Statement of Retained Earnings              Statement of Retained Earnings
13  Report Date 12/31/2001 12/31/2...           Statement of Retained Earnings
14  Previous ret earn... 2902007 2385854...     Statement of Retained Earnings
15  Cumulative effect of.. - - ...              Statement of Retained Earnings
16  Three-for-two stock split 117885 - 78076 -  Statement of Retained Earnings
17  Issuance of common.. 52753 75952...         Statement of Retained Earnings

Дальнейшие манипуляции можно выполнять, исправляя имена столбцов и удаляя ненужные строки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...