Как мне объединить шесть списков кортежей в pandas фрейм данных, используя первое значение каждого кортежа в качестве ключа? - PullRequest
0 голосов
/ 13 марта 2020

Я тестирую сервис с API, который может извлекать проанализированные корпоративные данные 10K. Для каждого извлеченного метри c (EBIT, ca sh, totalassets, et c) я храню квартальную дату и метрику c в кортеже, а каждый кортеж - в списке. Результатом являются шесть списков из 43 - 80 кортежей. Я хотел бы иметь фрейм данных со столбцом для корпоративного тикера, даты и метрик. Как я могу превратить то, что у меня есть (списки кортежей) в это?

Код ниже, чтобы извлечь данные (это пример, так что бесплатно):

import numpy as np
import json
import pandas as pd

content = requests.get(r'https://eodhistoricaldata.com/api/fundamentals/AAPL.US?api_token=OeAFFmMliFG5orCUuwAKQ8l4WWFQ67YX')

ebit_list = []
date_list = []
totalassets_list = []
cash_list = []
totalCurrentAssets_list = []
totalCurrentLiabilities_list = []


for i in content.json()['Financials']['Income_Statement']['quarterly']:

    try:
        ebit_list.append((i, float(content.json()['Financials']['Income_Statement']['quarterly'][i]['ebit'])))
    except:
        pass

    try:
        date_list.append(i)
    except:
        pass

    try:
        totalassets_list.append((i, float(content.json()['Financials']['Balance_Sheet']['quarterly'][i]['totalAssets'])))
    except:
        pass



for i in content.json()['Financials']['Balance_Sheet']['quarterly']:
    #print(i, float(content.json()['Financials']['Balance_Sheet']['quarterly']['2019-12-28']['totalCurrentLiabilities']))
    try:
        cash_list.append((i, float(content.json()['Financials']['Balance_Sheet']['quarterly'][i]['cash'])))
    except:
        pass

    try:
        totalCurrentAssets_list.append((i, float(content.json()['Financials']['Balance_Sheet']['quarterly'][i]['totalCurrentAssets'])))
    except:
        pass

    try:
        totalCurrentLiabilities_list.append((i, float(content.json()['Financials']['Balance_Sheet']['quarterly'][i]['totalCurrentLiabilities'])))
    except:
        pass

Я хотел бы получить кадр данных со всеми датами (то есть, если отсутствует метри c, заполняется ноль) и следующие столбцы:

date, ebit, totalassets, cash, totalCurrentAssets, totalCurrentLiabilities

Я не уверен, как извлечь кортежи и значения внутри каждого кортежа.

Ответы [ 3 ]

2 голосов
/ 16 марта 2020

Вы можете использовать функцию map в pandas.Series, чтобы сопоставить даты с нужными вам данными. Это вставит NaN для ячеек, у которых нет совпадающих значений, что упростит работу с пропущенными данными позже. Если вы все еще хотите заполнить нули, вы можете использовать fillna

# Create a dataframe using date
df = pd.DataFrame({'date': date_list})

# To avoid the code getting messy in the next steps
stuff = {'ebit': ebit_list, 'totalassets': totalassets_list, 'cash': cash_list, 'totalCurrentAssets': totalCurrentAssets_list, 'totalCurrentLiabilities': totalCurrentLiabilities_list}

for name, values in stuff.items():
    value_dict = {t[0]: t[1] for t in values}   # t is each tuple in the list
    df[name] = df['date'].map(value_dict)       # map will match the correct date to the value 

# assuming you need the dataframe to be sorted by date
df['date'] = pd.to_datetime(df['date'])         # we should use actual numbers instead of date string
df.sort_values('date', inplace=True, ignore_index=True)

# if you want to fill 0s to missing values
# df.fillna(0, inplace=True)

ignore_index аргумент в sort_values, чтобы убедиться, что индексы не перемешаны после сортировки. Если ваша pandas версия старая, она может дать TypeError: sort_values() got an unexpected keyword argument 'ignore_index' при сортировке. Если это так, вы должны использовать следующее для сброса индексов вместо

df.sort_values('date', inplace=True)
df.reset_index(inplace=True)

В конце это df

         date          ebit   totalassets          cash  totalCurrentAssets  totalCurrentLiabilities
0  2000-03-31           NaN  7.007000e+09           NaN                 NaN             1.853000e+09
1  2000-06-30           NaN  6.932000e+09           NaN                 NaN             1.873000e+09
2  2000-09-30           NaN  6.803000e+09           NaN                 NaN             1.933000e+09
3  2000-12-31  0.000000e+00  5.986000e+09           NaN                 NaN             1.637000e+09
4  2001-03-31  0.000000e+00  6.130000e+09           NaN                 NaN             1.795000e+09
..        ...           ...           ...           ...                 ...                      ...
75 2018-12-29  2.334600e+10  3.737190e+11  4.477100e+10        1.408280e+11             1.082830e+11
76 2019-03-30  1.341500e+10  3.419980e+11  3.798800e+10        1.233460e+11             9.377200e+10
77 2019-06-29  1.154400e+10  3.222390e+11  5.053000e+10        1.349730e+11             8.970400e+10
78 2019-09-28  1.562500e+10  3.385160e+11  4.884400e+10        1.628190e+11             1.057180e+11
79 2019-12-28  2.556900e+10  3.406180e+11  3.977100e+10        1.632310e+11             1.021610e+11
1 голос
/ 22 марта 2020

На самом деле мы можем немного упростить этот код, чтобы получить желаемый результат (и упростить его настройку в будущем!)

Готовый код приведен здесь, с более подробными пояснениями ниже:

import numpy as np
import json
import pandas as pd
import requests

content = requests.get(r'https://eodhistoricaldata.com/api/fundamentals/AAPL.US?api_token=OeAFFmMliFG5orCUuwAKQ8l4WWFQ67YX')

income_data = content.json()['Financials']['Income_Statement']['quarterly']
income = pd.DataFrame.from_dict(income_data).transpose().set_index("date")
income = income[['ebit']]

balance_data = content.json()['Financials']['Balance_Sheet']['quarterly']
balance = pd.DataFrame.from_dict(balance_data).transpose().set_index("date")
balance = balance[['totalAssets', 'cash', 'totalCurrentAssets', 'totalCurrentLiabilities']]

financials = income.merge(balance, left_index = True, right_index = True).fillna(0)

Финансовый DataFrame будет выглядеть следующим образом (показаны только данные за 2005-2009 гг.):

| date       |      ebit |   totalAssets |       cash |   totalCurrentAssets |   totalCurrentLiabilities |
|:-----------|----------:|--------------:|-----------:|---------------------:|--------------------------:|
| 2009-12-26 | 4.758e+09 |    5.3926e+10 | 7.609e+09  |           3.3332e+10 |                1.3097e+10 |
| 2009-09-26 | 0         |    4.7501e+10 | 5.263e+09  |           3.1555e+10 |                1.1506e+10 |
| 2009-06-27 | 1.732e+09 |    4.814e+10  | 5.605e+09  |           3.517e+10  |                1.6661e+10 |
| 2009-03-31 | 0         |    4.3237e+10 | 4.466e+09  |           0          |                1.3751e+10 |
| 2008-12-31 | 0         |    4.2787e+10 | 7.236e+09  |           0          |                1.4757e+10 |
| 2008-09-30 | 0         |    3.9572e+10 | 1.1875e+10 |           0          |                1.4092e+10 |
| 2008-06-30 | 0         |    3.1709e+10 | 9.373e+09  |           0          |                9.218e+09  |
| 2008-03-31 | 0         |    3.0471e+10 | 9.07e+09   |           0          |                9.634e+09  |
| 2007-12-31 | 0         |    3.0039e+10 | 9.162e+09  |           0          |                1.0535e+10 |
| 2007-09-30 | 0         |    2.5347e+10 | 9.352e+09  |           0          |                9.299e+09  |
| 2007-06-30 | 0         |    2.1647e+10 | 7.118e+09  |           0          |                6.992e+09  |
| 2007-03-31 | 0         |    1.8711e+10 | 7.095e+09  |           0          |                5.485e+09  |
| 2006-12-31 | 0         |    1.9461e+10 | 7.159e+09  |           0          |                7.337e+09  |
| 2006-09-30 | 0         |    1.7205e+10 | 6.392e+09  |           0          |                6.471e+09  |
| 2006-06-30 | 0         |    1.5114e+10 | 0          |           0          |                5.023e+09  |
| 2006-03-31 | 0         |    1.3911e+10 | 0          |           0          |                4.456e+09  |
| 2005-12-31 | 0         |    1.4181e+10 | 0          |           0          |                5.06e+09   |
| 2005-09-30 | 0         |    1.1551e+10 | 3.491e+09  |           0          |                3.484e+09  |
| 2005-06-30 | 0         |    1.0488e+10 | 0          |           0          |                3.123e+09  |
| 2005-03-31 | 0         |    1.0111e+10 | 0          |           0          |                3.352e+09  |

Результат content.json()['Financials']['Income_Statement']['quarterly'] - это словарь, в котором каждый ключ является дата и каждое значение являются вторым словарем с данными столбца.

{'2005-03-31': {'date': '2005-03-31',
                'filing_date': None,
                'currency_symbol': 'USD',
                'researchDevelopment': '120000000.00',
                ...},
'2005-06-30': {...},
...}

Поскольку это так, вы можете загрузить этот словарь непосредственно в pandas фрейм данных, используя

pd.DataFrame.from_dict(income_data).transpose().set_index("date")

Транспонирование необходимо, потому что структуры JSON. Pandas ожидает словарь в формате {'column name': data}. Поскольку ключи являются датами, первоначально вы получите DataFrame, где строки помечены как «totalAssets», «ca sh» и т. Д. c. и столбцы даты. команда transpose() переворачивает строки и столбцы в нужном вам формате. Последняя команда .set_index("date") предназначена для использования данных «дата» вместо начальной контрольной даты для согласованности и присвоения имени индексу. Это совершенно необязательно

Теперь этот DataFrame будет иметь каждый столбец из файла JSON, но вас интересуют только некоторые. Код

income = income[['ebit']]

выбирает только соответствующие столбцы из данных.

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

Финальная строка

financials = income.merge(balance, left_index = True, right_index = True).fillna(0)

объединяет две таблицы вместе, используя их индексы (в данном случае, столбец «дата»). fillna(0) гарантирует, что любые отсутствующие данные будут заменены нулевым значением, как вы и просили.

Если вам в конечном итоге понадобится добавить еще одну таблицу, например «Cash_Flow», вы будете использовать те же строки кода для создайте таблицу, выберите соответствующие столбцы и добавьте вторую строку слияния:

cashflow_data = content.json()['Financials']['Balance_Sheet']['quarterly']
cashflow = pd.DataFrame.from_dict(cashflow_data).transpose().set_index("date")
cashflow = cashflow[['accountsPayable', 'liabilitiesAndStockholdersEquity']]
...
financials.merge(cashflow, left_index = True, right_index = True).fillna(0)

В качестве бонуса, в вашем источнике довольно много данных JSON! Чтобы увидеть, какие столбцы доступны вам в любой данной таблице, используйте следующую команду:

cashflow.columns.sort_values()

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

      ['accountsPayable', 'accumulatedAmortization', 'accumulatedDepreciation',
       'accumulatedOtherComprehensiveIncome', 'additionalPaidInCapital',
       'capitalLeaseObligations', 'capitalSurpluse', 'cash',
       'cashAndShortTermInvestments', 'commonStock',
       'commonStockSharesOutstanding', 'commonStockTotalEquity',
       'currency_symbol', 'deferredLongTermAssetCharges',
       'deferredLongTermLiab', 'filing_date', 'goodWill', 'intangibleAssets',
       'inventory', 'liabilitiesAndStockholdersEquity', 'longTermDebt',
       'longTermDebtTotal', 'longTermInvestments', 'negativeGoodwill',
       'netReceivables', 'netTangibleAssets', 'nonCurrentAssetsTotal',
       'nonCurrentLiabilitiesOther', 'nonCurrentLiabilitiesTotal',
       'nonCurrrentAssetsOther', 'noncontrollingInterestInConsolidatedEntity',
       'otherAssets', 'otherCurrentAssets', 'otherCurrentLiab', 'otherLiab',
       'otherStockholderEquity', 'preferredStockRedeemable',
       'preferredStockTotalEquity', 'propertyPlantAndEquipmentGross',
       'propertyPlantEquipment', 'retainedEarnings',
       'retainedEarningsTotalEquity', 'shortLongTermDebt', 'shortTermDebt',
       'shortTermInvestments',
       'temporaryEquityRedeemableNoncontrollingInterests', 'totalAssets',
       'totalCurrentAssets', 'totalCurrentLiabilities', 'totalLiab',
       'totalPermanentEquity', 'totalStockholderEquity', 'treasuryStock',
       'warrants']

Это также очень полезно, когда в данных есть ошибки, например, в "capitalSurpluse" выше.

1 голос
/ 13 марта 2020

Я не могу заставить ваш пример работать, запросы не определены.

, но вот код, который может делать то, что вы хотите:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pandas as pd


def create_df(list_of_lists):
    pd.DataFrame({x[0]: pd.Series(x[1:]) for x in list of lists})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...