0

I am having trouble figuring out how to parse values from an API response as a list to a dataframe.

The 'games' API response is a list but it looks very similar to JSON. In other examples, I was able to create a dict. This list has multiple levels and is not as easy to create a dict. I am learning as I go and would appreciate any help.

Reference: https://github.com/CFBD/cfbd-python/blob/master/docs/GamesApi.md#get_team_game_stats

Python

from __future__ import print_function
import time
import cfbd
from cfbd.rest import ApiException
from pprint import pprint
import pandas as pd
from pandas.io.json import json_normalize
import json
import numpy as np
from datetime import datetime

# Configure API key authorization: ApiKeyAuth
configuration = cfbd.Configuration()
configuration.api_key['Authorization'] = 'xxxxxx'
configuration.api_key_prefix['Authorization'] = 'Bearer'
api_instance = cfbd.BettingApi(cfbd.ApiClient(configuration))

now = datetime.now()
start_year = 2020
end_year = now.year

for x,y in zip(range(start_year, end_year), range(1, 18)):
    year = x # int | Year filter
    week = y # int | Week filter (optional)

    try:
        api_instance = cfbd.GamesApi(cfbd.ApiClient(configuration))
        games = api_instance.get_team_game_stats(year=year, week=week)
        #game_stats_df = pd.DataFrame.from_records([dict(id = g.id, conference = g.conference, homeAway = g.homeAway) for g in games])

    except ApiException as e:
        print("Exception when calling BettingApi->get_calendar: %s\n" % e)

API Response

 {'id': 401238035,
 'teams': [{'conference': None,
            'homeAway': 'away',
            'points': 35,
            'school': 'Central Arkansas',
            'stats': [{'category': 'tacklesForLoss', 'stat': '8'},
                      {'category': 'defensiveTDs', 'stat': '1'},
                      {'category': 'tackles', 'stat': '61'},
                      {'category': 'sacks', 'stat': '0'},
                      {'category': 'qbHurries', 'stat': '1'},
                      {'category': 'passesDeflected', 'stat': '0'},
                      {'category': 'fumblesRecovered', 'stat': '2'},
                      {'category': 'rushingTDs', 'stat': '1'},
                      {'category': 'puntReturnYards', 'stat': '2'},
                      {'category': 'puntReturnTDs', 'stat': '0'},
                      {'category': 'puntReturns', 'stat': '2'},
                      {'category': 'passingTDs', 'stat': '3'},
                      {'category': 'kickReturnYards', 'stat': '116'},
                      {'category': 'kickReturnTDs', 'stat': '0'},
                      {'category': 'kickReturns', 'stat': '4'},
                      {'category': 'kickingPoints', 'stat': '5'},
                      {'category': 'interceptionYards', 'stat': '34'},
                      {'category': 'interceptionTDs', 'stat': '0'},
                      {'category': 'passesIntercepted', 'stat': '1'},
                      {'category': 'interceptions', 'stat': '1'},
                      {'category': 'fumblesLost', 'stat': '2'},
                      {'category': 'turnovers', 'stat': '3'},
                      {'category': 'totalPenaltiesYards', 'stat': '0-0'},
                      {'category': 'yardsPerRushAttempt', 'stat': '4.8'},
                      {'category': 'rushingAttempts', 'stat': '21'},
                      {'category': 'rushingYards', 'stat': '100'},
                      {'category': 'yardsPerPass', 'stat': '4.2'},
                      {'category': 'completionAttempts', 'stat': '25-46'},
                      {'category': 'netPassingYards', 'stat': '193'},
                      {'category': 'totalYards', 'stat': '293'},
                      {'category': 'fourthDownEff', 'stat': '0-0'},
                      {'category': 'thirdDownEff', 'stat': '0-0'},
                      {'category': 'firstDowns', 'stat': '0'}]},
           {'conference': 'Conference USA',
            'homeAway': 'home',
            'points': 45,
            'school': 'UAB',
            'stats': [{'category': 'tacklesForLoss', 'stat': '5'},
                      {'category': 'defensiveTDs', 'stat': '0'},
                      {'category': 'tackles', 'stat': '39'},
                      {'category': 'sacks', 'stat': '2'},
                      {'category': 'qbHurries', 'stat': '5'},
                      {'category': 'passesDeflected', 'stat': '5'},
                      {'category': 'fumblesRecovered', 'stat': '2'},
                      {'category': 'rushingTDs', 'stat': '3'},
                      {'category': 'puntReturnYards', 'stat': '-2'},
                      {'category': 'puntReturnTDs', 'stat': '0'},
                      {'category': 'puntReturns', 'stat': '1'},
                      {'category': 'passingTDs', 'stat': '3'},
                      {'category': 'kickReturnYards', 'stat': '49'},
                      {'category': 'kickReturnTDs', 'stat': '0'},
                      {'category': 'kickReturns', 'stat': '3'},
                      {'category': 'kickingPoints', 'stat': '9'},
                      {'category': 'interceptionYards', 'stat': '19'},
                      {'category': 'interceptionTDs', 'stat': '0'},
                      {'category': 'passesIntercepted', 'stat': '1'},
                      {'category': 'interceptions', 'stat': '1'},
                      {'category': 'fumblesLost', 'stat': '2'},
                      {'category': 'turnovers', 'stat': '3'},
                      {'category': 'totalPenaltiesYards', 'stat': '0-0'},
                      {'category': 'yardsPerRushAttempt', 'stat': '4.8'},
                      {'category': 'rushingAttempts', 'stat': '49'},
                      {'category': 'rushingYards', 'stat': '233'},
                      {'category': 'yardsPerPass', 'stat': '6.6'},
                      {'category': 'completionAttempts', 'stat': '24-34'},
                      {'category': 'netPassingYards', 'stat': '226'},
                      {'category': 'totalYards', 'stat': '459'},
                      {'category': 'fourthDownEff', 'stat': '0-0'},
                      {'category': 'thirdDownEff', 'stat': '0-0'},
                      {'category': 'firstDowns', 'stat': '0'}]}]}]
Helen
  • 87,344
  • 17
  • 243
  • 314
Tim R
  • 33
  • 4

1 Answers1

0

I was trying to help another person with this yesterday. The solution might be to use json_normalize importad like this: from pandas import json_normalize

I was able to clean up the API response a bit with https://jsonformatter.curiousconcept.com. Which also says it's RFC 8259 data (don't know anything about this, but maybe it helps):

data = {
   "id":401238035,
   "teams":[
      {
         "conference":"None",
         "homeAway":"away",
         "points":35,
         "school":"Central Arkansas",
         "stats":[
            {
               "category":"tacklesForLoss",
               "stat":"8"
            },
            {
               "category":"defensiveTDs",
               "stat":"1"
            },
            {
               "category":"tackles",
               "stat":"61"
            },
            {
               "category":"sacks",
               "stat":"0"
            },
            {
               "category":"qbHurries",
               "stat":"1"
            },
            {
               "category":"passesDeflected",
               "stat":"0"
            },
            {
               "category":"fumblesRecovered",
               "stat":"2"
            },
            {
               "category":"rushingTDs",
               "stat":"1"
            },
            {
               "category":"puntReturnYards",
               "stat":"2"
            },
            {
               "category":"puntReturnTDs",
               "stat":"0"
            },
            {
               "category":"puntReturns",
               "stat":"2"
            },
            {
               "category":"passingTDs",
               "stat":"3"
            },
            {
               "category":"kickReturnYards",
               "stat":"116"
            },
            {
               "category":"kickReturnTDs",
               "stat":"0"
            },
            {
               "category":"kickReturns",
               "stat":"4"
            },
            {
               "category":"kickingPoints",
               "stat":"5"
            },
            {
               "category":"interceptionYards",
               "stat":"34"
            },
            {
               "category":"interceptionTDs",
               "stat":"0"
            },
            {
               "category":"passesIntercepted",
               "stat":"1"
            },
            {
               "category":"interceptions",
               "stat":"1"
            },
            {
               "category":"fumblesLost",
               "stat":"2"
            },
            {
               "category":"turnovers",
               "stat":"3"
            },
            {
               "category":"totalPenaltiesYards",
               "stat":"0-0"
            },
            {
               "category":"yardsPerRushAttempt",
               "stat":"4.8"
            },
            {
               "category":"rushingAttempts",
               "stat":"21"
            },
            {
               "category":"rushingYards",
               "stat":"100"
            },
            {
               "category":"yardsPerPass",
               "stat":"4.2"
            },
            {
               "category":"completionAttempts",
               "stat":"25-46"
            },
            {
               "category":"netPassingYards",
               "stat":"193"
            },
            {
               "category":"totalYards",
               "stat":"293"
            },
            {
               "category":"fourthDownEff",
               "stat":"0-0"
            },
            {
               "category":"thirdDownEff",
               "stat":"0-0"
            },
            {
               "category":"firstDowns",
               "stat":"0"
            }
         ]
      },
      {
         "conference":"Conference USA",
         "homeAway":"home",
         "points":45,
         "school":"UAB",
         "stats":[
            {
               "category":"tacklesForLoss",
               "stat":"5"
            },
            {
               "category":"defensiveTDs",
               "stat":"0"
            },
            {
               "category":"tackles",
               "stat":"39"
            },
            {
               "category":"sacks",
               "stat":"2"
            },
            {
               "category":"qbHurries",
               "stat":"5"
            },
            {
               "category":"passesDeflected",
               "stat":"5"
            },
            {
               "category":"fumblesRecovered",
               "stat":"2"
            },
            {
               "category":"rushingTDs",
               "stat":"3"
            },
            {
               "category":"puntReturnYards",
               "stat":"-2"
            },
            {
               "category":"puntReturnTDs",
               "stat":"0"
            },
            {
               "category":"puntReturns",
               "stat":"1"
            },
            {
               "category":"passingTDs",
               "stat":"3"
            },
            {
               "category":"kickReturnYards",
               "stat":"49"
            },
            {
               "category":"kickReturnTDs",
               "stat":"0"
            },
            {
               "category":"kickReturns",
               "stat":"3"
            },
            {
               "category":"kickingPoints",
               "stat":"9"
            },
            {
               "category":"interceptionYards",
               "stat":"19"
            },
            {
               "category":"interceptionTDs",
               "stat":"0"
            },
            {
               "category":"passesIntercepted",
               "stat":"1"
            },
            {
               "category":"interceptions",
               "stat":"1"
            },
            {
               "category":"fumblesLost",
               "stat":"2"
            },
            {
               "category":"turnovers",
               "stat":"3"
            },
            {
               "category":"totalPenaltiesYards",
               "stat":"0-0"
            },
            {
               "category":"yardsPerRushAttempt",
               "stat":"4.8"
            },
            {
               "category":"rushingAttempts",
               "stat":"49"
            },
            {
               "category":"rushingYards",
               "stat":"233"
            },
            {
               "category":"yardsPerPass",
               "stat":"6.6"
            },
            {
               "category":"completionAttempts",
               "stat":"24-34"
            },
            {
               "category":"netPassingYards",
               "stat":"226"
            },
            {
               "category":"totalYards",
               "stat":"459"
            },
            {
               "category":"fourthDownEff",
               "stat":"0-0"
            },
            {
               "category":"thirdDownEff",
               "stat":"0-0"
            },
            {
               "category":"firstDowns",
               "stat":"0"
            }
         ]
      }
   ]
}

Maybe this helps:

import json
import pandas as pd
from pandas import json_normalize

new_data = data['teams'][0]

dict_data = dict(new_data)

result = json_normalize(new_data, ['stats'], record_prefix='_', errors='ignore')

result 

Output:

_category _stat
0 tacklesForLoss 8
1 defensiveTDs 1
2 tackles 61
3 sacks 0
4 qbHurries 1
5 passesDeflected 0
6 fumblesRecovered 2
7 rushingTDs 1
8 puntReturnYards 2
9 puntReturnTDs 0
10 puntReturns 2
11 passingTDs 3
12 kickReturnYards 116
13 kickReturnTDs 0
14 kickReturns 4
15 kickingPoints 5
16 interceptionYards 34
17 interceptionTDs 0
18 passesIntercepted 1
19 interceptions 1
20 fumblesLost 2
21 turnovers 3
22 totalPenaltiesYards 0-0
23 yardsPerRushAttempt 4.8
24 rushingAttempts 21
25 rushingYards 100
26 yardsPerPass 4.2
27 completionAttempts 25-46
28 netPassingYards 193
29 totalYards 293
30 fourthDownEff 0-0
31 thirdDownEff 0-0
32 firstDowns 0
thenarfer
  • 405
  • 2
  • 14
  • I think my main confusion is that the data is returned as type list. games = api_instance.get_team_game_stats(year=year, week=week) type(games) I tried your suggested and received the following error: Traceback (most recent call last): File "test4.py", line 34, in new_data = games['teams'][0] TypeError: list indices must be integers or slices, not st I have worked with JSON in similar scripts and never experienced this issue. – Tim R Aug 08 '21 at 23:04