преобразование данных JSON в несколько столбцов

#python #json #pandas

#python #json #pandas

Вопрос:

Я извлек коэффициенты игры в НФЛ из-odds-api. Используя pd.io.json.json_normalize, я могу создать фрейм данных, но данные недостаточно разбиты, чтобы удовлетворить мои потребности, поскольку все коэффициенты находятся в одном столбце.

Пример первой нормализованной записи:

 apidownload = {'sport_key': 'americanfootball_nfl', 'sport_nice': 'NFL', 'teams': ['Houston Texans', 'Kansas City Chiefs'], 'commence_time': 1599783600, 'home_team': 'Kansas City Chiefs', 'sites': [{'site_key': 'unibet', 'site_nice': 'Unibet', 'last_update': 1598541677, 'odds': {'spreads': {'odds': [1.91, 1.91], 'points': ['10.0', '-10.0']}}}, {'site_key': 'pointsbetus', 'site_nice': 'PointsBet (US)', 'last_update': 1598541706, 'odds': {'spreads': {'odds': [1.87, 1.95], 'points': ['10.5', '-10.5']}}}, {'site_key': 'gtbets', 'site_nice': 'GTbets', 'last_update': 1598541568, 'odds': {'spreads': {'odds': [1.877, 1.962], 'points': ['10', '-10']}}}, {'site_key': 'mybookieag', 'site_nice': 'MyBookie.ag', 'last_update': 1598541546, 'odds': {'spreads': {'odds': [1.87, 1.95], 'points': ['10.0', '-10.0']}}}, {'site_key': 'draftkings', 'site_nice': 'DraftKings', 'last_update': 1598541517, 'odds': {'spreads': {'odds': [1.91, 1.91], 'points': ['10.0', '-10.0']}}}, {'site_key': 'fanduel', 'site_nice': 'FanDuel', 'last_update': 1598541405, 'odds': {'spreads': {'odds': [2.0, 1.83], 'points': ['9.5', '-9.5']}}}, {'site_key': 'intertops', 'site_nice': 'Intertops', 'last_update': 1598541645, 'odds': {'spreads': {'odds': [1.9091, 1.9091], 'points': ['10.00', '-10.00']}}}, {'site_key': 'williamhill_us', 'site_nice': 'William Hill (US)', 'last_update': 1598541617, 'odds': {'spreads': {'odds': [1.87, 1.95], 'points': ['10.0', '-10.0']}}}, {'site_key': 'betrivers', 'site_nice': 'BetRivers', 'last_update': 1598541683, 'odds': {'spreads': {'odds': [1.91, 1.91], 'points': ['10.0', '-10.0']}}}], 'sites_count': 9}

df = pd.io.json.json_normalize(apidownload)
  

df имеет 7 столбцов с col6 «сайтами», содержащих все коэффициенты из 9 источников

 odds = pd.io.json.json_normalize(df.sites[0])
  

odds разбивает 9 источников, но в новом фрейме данных с 9 строками. У меня возникли проблемы с выяснением, как это сделать в одном и том же фрейме данных, чтобы он отображал информацию о команде / игре с соответствующими коэффициентами из каждого источника в отдельных столбцах.

Ответ №1:

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

 apidownload = {'sport_key': 'americanfootball_nfl', 'sport_nice': 'NFL', 'teams': ['Houston Texans', 'Kansas City Chiefs'], 'commence_time': 1599783600, 'home_team': 'Kansas City Chiefs', 'sites': [{'site_key': 'unibet', 'site_nice': 'Unibet', 'last_update': 1598541677, 'odds': {'spreads': {'odds': [1.91, 1.91], 'points': ['10.0', '-10.0']}}}, {'site_key': 'pointsbetus', 'site_nice': 'PointsBet (US)', 'last_update': 1598541706, 'odds': {'spreads': {'odds': [1.87, 1.95], 'points': ['10.5', '-10.5']}}}, {'site_key': 'gtbets', 'site_nice': 'GTbets', 'last_update': 1598541568, 'odds': {'spreads': {'odds': [1.877, 1.962], 'points': ['10', '-10']}}}, {'site_key': 'mybookieag', 'site_nice': 'MyBookie.ag', 'last_update': 1598541546, 'odds': {'spreads': {'odds': [1.87, 1.95], 'points': ['10.0', '-10.0']}}}, {'site_key': 'draftkings', 'site_nice': 'DraftKings', 'last_update': 1598541517, 'odds': {'spreads': {'odds': [1.91, 1.91], 'points': ['10.0', '-10.0']}}}, {'site_key': 'fanduel', 'site_nice': 'FanDuel', 'last_update': 1598541405, 'odds': {'spreads': {'odds': [2.0, 1.83], 'points': ['9.5', '-9.5']}}}, {'site_key': 'intertops', 'site_nice': 'Intertops', 'last_update': 1598541645, 'odds': {'spreads': {'odds': [1.9091, 1.9091], 'points': ['10.00', '-10.00']}}}, {'site_key': 'williamhill_us', 'site_nice': 'William Hill (US)', 'last_update': 1598541617, 'odds': {'spreads': {'odds': [1.87, 1.95], 'points': ['10.0', '-10.0']}}}, {'site_key': 'betrivers', 'site_nice': 'BetRivers', 'last_update': 1598541683, 'odds': {'spreads': {'odds': [1.91, 1.91], 'points': ['10.0', '-10.0']}}}], 'sites_count': 9}


import pandas as pd
import re


def flatten_json(y):
    out = {}

    def flatten(x, name=''):
        if type(x) is dict:
            for a in x:
                flatten(x[a], name   a   '_')
        elif type(x) is list:
            i = 0
            for a in x:
                flatten(a, name   str(i)   '_')
                i  = 1
        else:
            out[name[:-1]] = x

    flatten(y)
    return out

flat = flatten_json(apidownload)                      


results = pd.DataFrame()
special_cols = []

columns_list = list(flat.keys())
for item in columns_list:
    try:
        row_idx = re.findall(r'_(d )_', item )[0]
    except:
        special_cols.append(item)
        continue
    column = re.findall(r'_d _(.*)', item )[0]
    

    row_idx = int(row_idx)
    value = flat[item]

    results.loc[row_idx, column] = value

for item in special_cols:
    results[item] = flat[item] 
  

Вывод:

 print(results.to_string())
         site_key          site_nice   last_update  odds_spreads_odds_0  odds_spreads_odds_1 odds_spreads_points_0 odds_spreads_points_1             sport_key sport_nice         teams_0             teams_1  commence_time           home_team  sites_count
0          unibet             Unibet  1.598542e 09               1.9100               1.9100                  10.0                 -10.0  americanfootball_nfl        NFL  Houston Texans  Kansas City Chiefs     1599783600  Kansas City Chiefs            9
1     pointsbetus     PointsBet (US)  1.598542e 09               1.8700               1.9500                  10.5                 -10.5  americanfootball_nfl        NFL  Houston Texans  Kansas City Chiefs     1599783600  Kansas City Chiefs            9
2          gtbets             GTbets  1.598542e 09               1.8770               1.9620                    10                   -10  americanfootball_nfl        NFL  Houston Texans  Kansas City Chiefs     1599783600  Kansas City Chiefs            9
3      mybookieag        MyBookie.ag  1.598542e 09               1.8700               1.9500                  10.0                 -10.0  americanfootball_nfl        NFL  Houston Texans  Kansas City Chiefs     1599783600  Kansas City Chiefs            9
4      draftkings         DraftKings  1.598542e 09               1.9100               1.9100                  10.0                 -10.0  americanfootball_nfl        NFL  Houston Texans  Kansas City Chiefs     1599783600  Kansas City Chiefs            9
5         fanduel            FanDuel  1.598541e 09               2.0000               1.8300                   9.5                  -9.5  americanfootball_nfl        NFL  Houston Texans  Kansas City Chiefs     1599783600  Kansas City Chiefs            9
6       intertops          Intertops  1.598542e 09               1.9091               1.9091                 10.00                -10.00  americanfootball_nfl        NFL  Houston Texans  Kansas City Chiefs     1599783600  Kansas City Chiefs            9
7  williamhill_us  William Hill (US)  1.598542e 09               1.8700               1.9500                  10.0                 -10.0  americanfootball_nfl        NFL  Houston Texans  Kansas City Chiefs     1599783600  Kansas City Chiefs            9
8       betrivers          BetRivers  1.598542e 09               1.9100               1.9100                  10.0                 -10.0  americanfootball_nfl        NFL  Houston Texans  Kansas City Chiefs     1599783600  Kansas City Chiefs            9
  

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

1. Фактическая загрузка API содержит несколько записей (я воссоздал первую для своего вопроса), поэтому я получаю коэффициенты в отдельных столбцах, а не в строках.