sportsref/nfl/pbp.py
def _clean_features(struct):
    """Cleans up the features collected in parse_play_details.

    :struct: Pandas Series of features parsed from details string.
    :returns: the same dict, but with cleaner features (e.g., convert bools,
    ints, etc.)
    """
    struct = dict(struct)
    # First, clean up play type bools
    ptypes = ['isKickoff', 'isTimeout', 'isFieldGoal', 'isPunt', 'isKneel',
              'isSpike', 'isXP', 'isTwoPoint', 'isPresnapPenalty', 'isPass',
              'isRun']
    for pt in ptypes:
        struct[pt] = struct[pt] if pd.notnull(struct.get(pt)) else False
    # Second, clean up other existing variables on a one-off basis
    struct['callUpheld'] = struct.get('callUpheld') == 'upheld'
    struct['fgGood'] = struct.get('fgGood') == 'good'
    struct['isBlocked'] = struct.get('isBlocked') == 'blocked'
    struct['isComplete'] = struct.get('isComplete') == 'complete'
    struct['isFairCatch'] = struct.get('isFairCatch') == 'fair catch'
    struct['isMuffedCatch'] = pd.notnull(struct.get('isMuffedCatch'))
    struct['isNoPlay'] = (
        ' (no play)' in struct['detail'] and
        'penalty enforced in end zone' not in struct['detail']
        if struct.get('detail') else False)
    struct['isOnside'] = struct.get('isOnside') == 'onside'
    struct['isSack'] = pd.notnull(struct.get('sackYds'))
    struct['isSafety'] = (struct.get('isSafety') == ', safety' or
                          (struct.get('detail') and
                           'enforced in end zone, safety' in struct['detail']))
    struct['isTD'] = struct.get('isTD') == ', touchdown'
    struct['isTouchback'] = struct.get('isTouchback') == ', touchback'
    struct['oob'] = pd.notnull(struct.get('oob'))
    struct['passLoc'] = PASS_OPTS.get(struct.get('passLoc'), np.nan)
    if struct['isPass']:
        pyds = struct['passYds']
        struct['passYds'] = pyds if pd.notnull(pyds) else 0
    if pd.notnull(struct['penalty']):
        struct['penalty'] = struct['penalty'].strip()
    struct['penDeclined'] = struct.get('penDeclined') == 'Declined'
    if struct['quarter'] == 'OT':
        struct['quarter'] = 5
    struct['rushDir'] = RUSH_OPTS.get(struct.get('rushDir'), np.nan)
    if struct['isRun']:
        ryds = struct['rushYds']
        struct['rushYds'] = ryds if pd.notnull(ryds) else 0
    year = struct.get('season', np.nan)
    struct['timeoutTeam'] = sportsref.nfl.teams.team_ids(year).get(
        struct.get('timeoutTeam'), np.nan
    )
    struct['twoPointSuccess'] = struct.get('twoPointSuccess') == 'succeeds'
    struct['xpGood'] = struct.get('xpGood') == 'good'

    # Third, ensure types are correct
    bool_vars = [
        'fgGood', 'isBlocked', 'isChallenge', 'isComplete', 'isFairCatch',
        'isFieldGoal', 'isKickoff', 'isKneel', 'isLateral', 'isNoPlay',
        'isPass', 'isPresnapPenalty', 'isPunt', 'isRun', 'isSack', 'isSafety',
        'isSpike', 'isTD', 'isTimeout', 'isTouchback', 'isTwoPoint', 'isXP',
        'isMuffedCatch', 'oob', 'penDeclined', 'twoPointSuccess', 'xpGood'
    ]
    int_vars = [
        'down', 'fgBlockRetYds', 'fgDist', 'fumbRecYdLine', 'fumbRetYds',
        'intRetYds', 'intYdLine', 'koRetYds', 'koYds', 'muffRetYds',
        'pbp_score_aw', 'pbp_score_hm', 'passYds', 'penYds', 'puntBlockRetYds',
        'puntRetYds', 'puntYds', 'quarter', 'rushYds', 'sackYds', 'timeoutNum',
        'ydLine', 'yds_to_go'
    ]
    float_vars = [
        'exp_pts_after', 'exp_pts_before', 'home_wp'
    ]
    string_vars = [
        'challenger', 'detail', 'fairCatcher', 'fgBlockRecoverer',
        'fgBlocker', 'fgKicker', 'fieldSide', 'fumbForcer',
        'fumbRecFieldSide', 'fumbRecoverer', 'fumbler', 'intFieldSide',
        'interceptor', 'kneelQB', 'koKicker', 'koReturner', 'muffRecoverer',
        'muffedBy', 'passLoc', 'passer', 'penOn', 'penalty',
        'puntBlockRecoverer', 'puntBlocker', 'puntReturner', 'punter',
        'qtr_time_remain', 'rushDir', 'rusher', 'sacker1', 'sacker2',
        'spikeQB', 'tackler1', 'tackler2', 'target', 'timeoutTeam',
        'xpKicker'
    ]
    for var in bool_vars:
        struct[var] = struct.get(var) is True
    for var in int_vars:
        try:
            struct[var] = int(struct.get(var))
        except (ValueError, TypeError):
            struct[var] = np.nan
    for var in float_vars:
        try:
            struct[var] = float(struct.get(var))
        except (ValueError, TypeError):
            struct[var] = np.nan
    for var in string_vars:
        if var not in struct or pd.isnull(struct[var]) or var == '':
            struct[var] = np.nan

    # Fourth, create new helper variables based on parsed variables
    # creating fieldSide and ydline from location
    if struct['isXP']:
        struct['fieldSide'] = struct['ydLine'] = np.nan
    else:
        fieldSide, ydline = _loc_to_features(struct.get('location'))
        struct['fieldSide'] = fieldSide
        struct['ydLine'] = ydline
    # creating secsElapsed (in entire game) from qtr_time_remain and quarter
    if pd.notnull(struct.get('qtr_time_remain')):
        qtr = struct['quarter']
        mins, secs = map(int, struct['qtr_time_remain'].split(':'))
        struct['secsElapsed'] = qtr * 900 - mins * 60 - secs
    # creating columns for turnovers
    struct['isInt'] = pd.notnull(struct.get('interceptor'))
    struct['isFumble'] = pd.notnull(struct.get('fumbler'))
    # create column for isPenalty
    struct['isPenalty'] = pd.notnull(struct.get('penalty'))
    # create columns for EPA
    struct['team_epa'] = struct['exp_pts_after'] - struct['exp_pts_before']
    struct['opp_epa'] = struct['exp_pts_before'] - struct['exp_pts_after']
    return pd.Series(struct)
def _clean_features(struct):
    """Cleans up the features collected in parse_play_details.

    :struct: Pandas Series of features parsed from details string.
    :returns: the same dict, but with cleaner features (e.g., convert bools,
    ints, etc.)
    """
    struct = dict(struct)
    # First, clean up play type bools
    ptypes = ['isKickoff', 'isTimeout', 'isFieldGoal', 'isPunt', 'isKneel',
              'isSpike', 'isXP', 'isTwoPoint', 'isPresnapPenalty', 'isPass',
              'isRun']
    for pt in ptypes:
        struct[pt] = struct[pt] if pd.notnull(struct.get(pt)) else False
    # Second, clean up other existing variables on a one-off basis
    struct['callUpheld'] = struct.get('callUpheld') == 'upheld'
    struct['fgGood'] = struct.get('fgGood') == 'good'
    struct['isBlocked'] = struct.get('isBlocked') == 'blocked'
    struct['isComplete'] = struct.get('isComplete') == 'complete'
    struct['isFairCatch'] = struct.get('isFairCatch') == 'fair catch'
    struct['isMuffedCatch'] = pd.notnull(struct.get('isMuffedCatch'))
    struct['isNoPlay'] = (
        ' (no play)' in struct['detail'] and
        'penalty enforced in end zone' not in struct['detail']
        if struct.get('detail') else False)
    struct['isOnside'] = struct.get('isOnside') == 'onside'
    struct['isSack'] = pd.notnull(struct.get('sackYds'))
    struct['isSafety'] = (struct.get('isSafety') == ', safety' or
                          (struct.get('detail') and
                           'enforced in end zone, safety' in struct['detail']))
    struct['isTD'] = struct.get('isTD') == ', touchdown'
    struct['isTouchback'] = struct.get('isTouchback') == ', touchback'
    struct['oob'] = pd.notnull(struct.get('oob'))
    struct['passLoc'] = PASS_OPTS.get(struct.get('passLoc'), np.nan)
    if struct['isPass']:
        pyds = struct['passYds']
        struct['passYds'] = pyds if pd.notnull(pyds) else 0
    if pd.notnull(struct['penalty']):
        struct['penalty'] = struct['penalty'].strip()
    struct['penDeclined'] = struct.get('penDeclined') == 'Declined'
    if struct['quarter'] == 'OT':
        struct['quarter'] = 5
    struct['rushDir'] = RUSH_OPTS.get(struct.get('rushDir'), np.nan)
    if struct['isRun']:
        ryds = struct['rushYds']
        struct['rushYds'] = ryds if pd.notnull(ryds) else 0
    year = struct.get('season', np.nan)
    struct['timeoutTeam'] = sportsref.nfl.teams.team_ids(year).get(
        struct.get('timeoutTeam'), np.nan
    )
    struct['twoPointSuccess'] = struct.get('twoPointSuccess') == 'succeeds'
    struct['xpGood'] = struct.get('xpGood') == 'good'

    # Third, ensure types are correct
    bool_vars = [
        'fgGood', 'isBlocked', 'isChallenge', 'isComplete', 'isFairCatch',
        'isFieldGoal', 'isKickoff', 'isKneel', 'isLateral', 'isNoPlay',
        'isPass', 'isPresnapPenalty', 'isPunt', 'isRun', 'isSack', 'isSafety',
        'isSpike', 'isTD', 'isTimeout', 'isTouchback', 'isTwoPoint', 'isXP',
        'isMuffedCatch', 'oob', 'penDeclined', 'twoPointSuccess', 'xpGood'
    ]
    int_vars = [
        'down', 'fgBlockRetYds', 'fgDist', 'fumbRecYdLine', 'fumbRetYds',
        'intRetYds', 'intYdLine', 'koRetYds', 'koYds', 'muffRetYds',
        'pbp_score_aw', 'pbp_score_hm', 'passYds', 'penYds', 'puntBlockRetYds',
        'puntRetYds', 'puntYds', 'quarter', 'rushYds', 'sackYds', 'timeoutNum',
        'ydLine', 'yds_to_go'
    ]
    float_vars = [
        'exp_pts_after', 'exp_pts_before', 'home_wp'
    ]
    string_vars = [
        'challenger', 'detail', 'fairCatcher', 'fgBlockRecoverer',
        'fgBlocker', 'fgKicker', 'fieldSide', 'fumbForcer',
        'fumbRecFieldSide', 'fumbRecoverer', 'fumbler', 'intFieldSide',
        'interceptor', 'kneelQB', 'koKicker', 'koReturner', 'muffRecoverer',
        'muffedBy', 'passLoc', 'passer', 'penOn', 'penalty',
        'puntBlockRecoverer', 'puntBlocker', 'puntReturner', 'punter',
        'qtr_time_remain', 'rushDir', 'rusher', 'sacker1', 'sacker2',
        'spikeQB', 'tackler1', 'tackler2', 'target', 'timeoutTeam',
        'xpKicker'
    ]
    for var in bool_vars:
        struct[var] = struct.get(var) is True
    for var in int_vars:
        try:
            struct[var] = int(struct.get(var))
        except (ValueError, TypeError):
            struct[var] = np.nan
    for var in float_vars:
        try:
            struct[var] = float(struct.get(var))
        except (ValueError, TypeError):
            struct[var] = np.nan
    for var in string_vars:
        if var not in struct or pd.isnull(struct[var]) or var == '':
            struct[var] = np.nan

    # Fourth, create new helper variables based on parsed variables
    # creating fieldSide and ydline from location
    if struct['isXP']:
        struct['fieldSide'] = struct['ydLine'] = np.nan
    else:
        fieldSide, ydline = _loc_to_features(struct.get('location'))
        struct['fieldSide'] = fieldSide
        struct['ydLine'] = ydline
    # creating secsElapsed (in entire game) from qtr_time_remain and quarter
    if pd.notnull(struct.get('qtr_time_remain')):
        qtr = struct['quarter']
        mins, secs = map(int, struct['qtr_time_remain'].split(':'))
        struct['secsElapsed'] = qtr * 900 - mins * 60 - secs
    # creating columns for turnovers
    struct['isInt'] = pd.notnull(struct.get('interceptor'))
    struct['isFumble'] = pd.notnull(struct.get('fumbler'))
    # create column for isPenalty
    struct['isPenalty'] = pd.notnull(struct.get('penalty'))
    # create columns for EPA
    struct['team_epa'] = struct['exp_pts_after'] - struct['exp_pts_before']
    struct['opp_epa'] = struct['exp_pts_before'] - struct['exp_pts_after']
    return pd.Series(struct)
def _clean_features ( struct ) : struct = dict ( struct ) # First, clean up play type bools ptypes = [ 'isKickoff' , 'isTimeout' , 'isFieldGoal' , 'isPunt' , 'isKneel' , 'isSpike' , 'isXP' , 'isTwoPoint' , 'isPresnapPenalty' , 'isPass' , 'isRun' ] for pt in ptypes : struct [ pt ] = struct [ pt ] if pd . notnull ( struct . get ( pt ) ) else False # Second, clean up other existing variables on a one-off basis struct [ 'callUpheld' ] = struct . get ( 'callUpheld' ) == 'upheld' struct [ 'fgGood' ] = struct . get ( 'fgGood' ) == 'good' struct [ 'isBlocked' ] = struct . get ( 'isBlocked' ) == 'blocked' struct [ 'isComplete' ] = struct . get ( 'isComplete' ) == 'complete' struct [ 'isFairCatch' ] = struct . get ( 'isFairCatch' ) == 'fair catch' struct [ 'isMuffedCatch' ] = pd . notnull ( struct . get ( 'isMuffedCatch' ) ) struct [ 'isNoPlay' ] = ( ' (no play)' in struct [ 'detail' ] and 'penalty enforced in end zone' not in struct [ 'detail' ] if struct . get ( 'detail' ) else False ) struct [ 'isOnside' ] = struct . get ( 'isOnside' ) == 'onside' struct [ 'isSack' ] = pd . notnull ( struct . get ( 'sackYds' ) ) struct [ 'isSafety' ] = ( struct . get ( 'isSafety' ) == ', safety' or ( struct . get ( 'detail' ) and 'enforced in end zone, safety' in struct [ 'detail' ] ) ) struct [ 'isTD' ] = struct . get ( 'isTD' ) == ', touchdown' struct [ 'isTouchback' ] = struct . get ( 'isTouchback' ) == ', touchback' struct [ 'oob' ] = pd . notnull ( struct . get ( 'oob' ) ) struct [ 'passLoc' ] = PASS_OPTS . get ( struct . get ( 'passLoc' ) , np . nan ) if struct [ 'isPass' ] : pyds = struct [ 'passYds' ] struct [ 'passYds' ] = pyds if pd . notnull ( pyds ) else 0 if pd . notnull ( struct [ 'penalty' ] ) : struct [ 'penalty' ] = struct [ 'penalty' ] . strip ( ) struct [ 'penDeclined' ] = struct . get ( 'penDeclined' ) == 'Declined' if struct [ 'quarter' ] == 'OT' : struct [ 'quarter' ] = 5 struct [ 'rushDir' ] = RUSH_OPTS . get ( struct . get ( 'rushDir' ) , np . nan ) if struct [ 'isRun' ] : ryds = struct [ 'rushYds' ] struct [ 'rushYds' ] = ryds if pd . notnull ( ryds ) else 0 year = struct . get ( 'season' , np . nan ) struct [ 'timeoutTeam' ] = sportsref . nfl . teams . team_ids ( year ) . get ( struct . get ( 'timeoutTeam' ) , np . nan ) struct [ 'twoPointSuccess' ] = struct . get ( 'twoPointSuccess' ) == 'succeeds' struct [ 'xpGood' ] = struct . get ( 'xpGood' ) == 'good' # Third, ensure types are correct bool_vars = [ 'fgGood' , 'isBlocked' , 'isChallenge' , 'isComplete' , 'isFairCatch' , 'isFieldGoal' , 'isKickoff' , 'isKneel' , 'isLateral' , 'isNoPlay' , 'isPass' , 'isPresnapPenalty' , 'isPunt' , 'isRun' , 'isSack' , 'isSafety' , 'isSpike' , 'isTD' , 'isTimeout' , 'isTouchback' , 'isTwoPoint' , 'isXP' , 'isMuffedCatch' , 'oob' , 'penDeclined' , 'twoPointSuccess' , 'xpGood' ] int_vars = [ 'down' , 'fgBlockRetYds' , 'fgDist' , 'fumbRecYdLine' , 'fumbRetYds' , 'intRetYds' , 'intYdLine' , 'koRetYds' , 'koYds' , 'muffRetYds' , 'pbp_score_aw' , 'pbp_score_hm' , 'passYds' , 'penYds' , 'puntBlockRetYds' , 'puntRetYds' , 'puntYds' , 'quarter' , 'rushYds' , 'sackYds' , 'timeoutNum' , 'ydLine' , 'yds_to_go' ] float_vars = [ 'exp_pts_after' , 'exp_pts_before' , 'home_wp' ] string_vars = [ 'challenger' , 'detail' , 'fairCatcher' , 'fgBlockRecoverer' , 'fgBlocker' , 'fgKicker' , 'fieldSide' , 'fumbForcer' , 'fumbRecFieldSide' , 'fumbRecoverer' , 'fumbler' , 'intFieldSide' , 'interceptor' , 'kneelQB' , 'koKicker' , 'koReturner' , 'muffRecoverer' , 'muffedBy' , 'passLoc' , 'passer' , 'penOn' , 'penalty' , 'puntBlockRecoverer' , 'puntBlocker' , 'puntReturner' , 'punter' , 'qtr_time_remain' , 'rushDir' , 'rusher' , 'sacker1' , 'sacker2' , 'spikeQB' , 'tackler1' , 'tackler2' , 'target' , 'timeoutTeam' , 'xpKicker' ] for var in bool_vars : struct [ var ] = struct . get ( var ) is True for var in int_vars : try : struct [ var ] = int ( struct . get ( var ) ) except ( ValueError , TypeError ) : struct [ var ] = np . nan for var in float_vars : try : struct [ var ] = float ( struct . get ( var ) ) except ( ValueError , TypeError ) : struct [ var ] = np . nan for var in string_vars : if var not in struct or pd . isnull ( struct [ var ] ) or var == '' : struct [ var ] = np . nan # Fourth, create new helper variables based on parsed variables # creating fieldSide and ydline from location if struct [ 'isXP' ] : struct [ 'fieldSide' ] = struct [ 'ydLine' ] = np . nan else : fieldSide , ydline = _loc_to_features ( struct . get ( 'location' ) ) struct [ 'fieldSide' ] = fieldSide struct [ 'ydLine' ] = ydline # creating secsElapsed (in entire game) from qtr_time_remain and quarter if pd . notnull ( struct . get ( 'qtr_time_remain' ) ) : qtr = struct [ 'quarter' ] mins , secs = map ( int , struct [ 'qtr_time_remain' ] . split ( ':' ) ) struct [ 'secsElapsed' ] = qtr * 900 - mins * 60 - secs # creating columns for turnovers struct [ 'isInt' ] = pd . notnull ( struct . get ( 'interceptor' ) ) struct [ 'isFumble' ] = pd . notnull ( struct . get ( 'fumbler' ) ) # create column for isPenalty struct [ 'isPenalty' ] = pd . notnull ( struct . get ( 'penalty' ) ) # create columns for EPA struct [ 'team_epa' ] = struct [ 'exp_pts_after' ] - struct [ 'exp_pts_before' ] struct [ 'opp_epa' ] = struct [ 'exp_pts_before' ] - struct [ 'exp_pts_after' ] return pd . Series ( struct )
Cleans up the features collected in parse_play_details.

    :struct: Pandas Series of features parsed from details string.
    :returns: the same dict, but with cleaner features (e.g., convert bools,
    ints, etc.)
Cleans up the features collected in parse_play_details .