Пренасяне на PyMC2 код към PyMC3 - йерархичен модел за спортни анализи

Опитах следния код, но срещнах проблеми. Мисля, че .values ​​е проблемът, но как да кодирам това като обект Theano?

Следното е моят източник на данни

home_team,away_team,home_score,away_score
Wales,Italy,23,15
France,England,26,24
Ireland,Scotland,28,6
Ireland,Wales,26,3
Scotland,England,0,20
France,Italy,30,10
Wales,France,27,6
Italy,Scotland,20,21
England,Ireland,13,10
Ireland,Italy,46,7
Scotland,France,17,19
England,Wales,29,18
Italy,England,11,52
Wales,Scotland,51,3
France,Ireland,20,22

Ето PyMC2 кода, който работи: data_file = DATA_DIR + 'results_2014.csv'

df = pd.read_csv(data_file, sep=',')
# Or whatever it takes to get this into a data frame.
teams = df.home_team.unique()
teams = pd.DataFrame(teams, columns=['team'])
teams['i'] = teams.index
df = pd.merge(df, teams, left_on='home_team', right_on='team', how='left')
df = df.rename(columns = {'i': 'i_home'}).drop('team', 1)
df = pd.merge(df, teams, left_on='away_team', right_on='team', how='left')
df = df.rename(columns = {'i': 'i_away'}).drop('team', 1)
observed_home_goals = df.home_score.values
observed_away_goals = df.away_score.values
home_team = df.i_home.values
away_team = df.i_away.values
num_teams = len(df.i_home.drop_duplicates())
num_games = len(home_team)
g = df.groupby('i_away')
att_starting_points = np.log(g.away_score.mean())
g = df.groupby('i_home')
def_starting_points = -np.log(g.away_score.mean())

#hyperpriors
home = pymc.Normal('home', 0, .0001, value=0)
tau_att = pymc.Gamma('tau_att', .1, .1, value=10)
tau_def = pymc.Gamma('tau_def', .1, .1, value=10)
intercept = pymc.Normal('intercept', 0, .0001, value=0)
#team-specific parameters
atts_star = pymc.Normal("atts_star", 
                        mu=0, 
                        tau=tau_att, 
                        size=num_teams, 
                        value=att_starting_points.values)
defs_star = pymc.Normal("defs_star", 
                        mu=0, 
                        tau=tau_def, 
                        size=num_teams, 
                        value=def_starting_points.values) 

# trick to code the sum to zero constraint
@pymc.deterministic
def atts(atts_star=atts_star):
    atts = atts_star.copy()
    atts = atts - np.mean(atts_star)
    return atts

@pymc.deterministic
def defs(defs_star=defs_star):
    defs = defs_star.copy()
    defs = defs - np.mean(defs_star)
    return defs

@pymc.deterministic
def home_theta(home_team=home_team, 
               away_team=away_team, 
               home=home, 
               atts=atts, 
               defs=defs, 
               intercept=intercept): 
    return np.exp(intercept + 
                  home + 
                  atts[home_team] + 
                  defs[away_team])

@pymc.deterministic
def away_theta(home_team=home_team, 
               away_team=away_team, 
               home=home, 
               atts=atts, 
               defs=defs, 
               intercept=intercept): 
    return np.exp(intercept + 
                  atts[away_team] + 
                  defs[home_team])   

home_points = pymc.Poisson('home_points', 
                          mu=home_theta, 
                          value=observed_home_goals, 
                          observed=True)
away_points = pymc.Poisson('away_points', 
                          mu=away_theta, 
                          value=observed_away_goals, 
                          observed=True)

mcmc = pymc.MCMC([home, intercept, tau_att, tau_def, 
                  home_theta, away_theta, 
                  atts_star, defs_star, atts, defs, 
                  home_points, away_points])
map_ = pymc.MAP( mcmc )
map_.fit()

mcmc.sample(200000, 40000, 20)

Моят опит за пренасяне към PyMC3 :) И включвам кода за пререкания. Определих своя собствена директория с данни и т.н.

data_file = DATA_DIR + 'results_2014.csv'

df = pd.read_csv(data_file, sep=',')
# Or whatever it takes to get this into a data frame.
teams = df.home_team.unique()
teams = pd.DataFrame(teams, columns=['team'])
teams['i'] = teams.index
df = pd.merge(df, teams, left_on='home_team', right_on='team', how='left')
df = df.rename(columns = {'i': 'i_home'}).drop('team', 1)
df = pd.merge(df, teams, left_on='away_team', right_on='team', how='left')
df = df.rename(columns = {'i': 'i_away'}).drop('team', 1)
observed_home_goals = df.home_score.values
observed_away_goals = df.away_score.values
home_team = df.i_home.values
away_team = df.i_away.values
num_teams = len(df.i_home.drop_duplicates())
num_games = len(home_team)
g = df.groupby('i_away')
att_starting_points = np.log(g.away_score.mean())
g = df.groupby('i_home')
def_starting_points = -np.log(g.away_score.mean())

import theano.tensor as T
import pymc3 as pm3
#hyperpriors


x = att_starting_points.values
y = def_starting_points.values
model = pm.Model()
with pm3.Model() as model:
    home3 = pm3.Normal('home', 0, .0001)
    tau_att3 = pm3.Gamma('tau_att', .1, .1)
    tau_def3 = pm3.Gamma('tau_def', .1, .1)
    intercept3 = pm3.Normal('intercept', 0, .0001)
    #team-specific parameters
    atts_star3 = pm3.Normal("atts_star", 
                        mu=0, 
                        tau=tau_att3, 
                        observed=x)
    defs_star3 = pm3.Normal("defs_star", 
                        mu=0, 
                        tau=tau_def3,  
                        observed=y) 
    #Seems to be the error here. 
    atts = pm3.Deterministic('regression', 
    atts_star3 - np.mean(atts_star3))
    home_theta3 = pm3.Deterministic('regression', 
    T.exp(intercept3 + atts[away_team] + defs[home_team]))
atts = pm3.Deterministic('regression', atts_star3 - np.mean(atts_star3))
    home_theta3 = pm3.Deterministic('regression', T.exp(intercept3 +     atts[away_team] + defs[home_team]))
    # Unknown model parameters
    home_points3 = pm3.Poisson('home_points', mu=home_theta3, observed=observed_home_goals)
    away_points3 = pm3.Poisson('away_points', mu=home_theta3, observed=observed_away_goals)
    start = pm3.find_MAP()
    step = pm3.NUTS(state=start)
    trace = pm3.sample(2000, step, start=start, progressbar=True)

    pm3.traceplot(trace)

И получавам грешка, че стойностите не са обект на Theano. Мисля, че това е частта .values ​​по-горе. Но съм объркан как да преобразувам това в тензор на Теано. Тензорите ме объркват :)

И грешката за яснота, защото не съм разбрал нещо в синтаксиса на PyMC3.

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-71-ce51c1a64412> in <module>()
     23 
     24     #Seems to be the error here.
---> 25     atts = pm3.Deterministic('regression', atts_star3 - np.mean(atts_star3))
     26     home_theta3 = pm3.Deterministic('regression', T.exp(intercept3 + atts[away_team] + defs[home_team]))
     27 

/Users/peadarcoyle/anaconda/lib/python3.4/site-packages/numpy/core/fromnumeric.py in mean(a, axis, dtype, out, keepdims)
   2733 
   2734     return _methods._mean(a, axis=axis, dtype=dtype,
-> 2735                             out=out, keepdims=keepdims)
   2736 
   2737 def std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False):

/Users/peadarcoyle/anaconda/lib/python3.4/site-packages/numpy/core/_methods.py in _mean(a, axis, dtype, out, keepdims)
     71         ret = ret.dtype.type(ret / rcount)
     72     else:
---> 73         ret = ret / rcount
     74 
     75     return ret

TypeError: unsupported operand type(s) for /: 'ObservedRV' and 'int'

person Peadar Coyle    schedule 12.06.2015    source източник
comment
Можете ли да добавите данни, за да мога да възпроизведа вашата грешка? Малък симулиран пример ще бъде добре, стига да повдига същата грешка, която откривате с вашите реални данни. напр. stackoverflow.com/help/mcve   -  person Abraham D Flaxman    schedule 12.06.2015
comment
Авраам I поправи това и добави това.   -  person Peadar Coyle    schedule 12.06.2015
comment
Благодаря за напомнянето.   -  person Peadar Coyle    schedule 12.06.2015
comment
Не би трябвало да е необходимо да преобразувате масиви в тензори. Все още не виждам грешката, която всъщност получавате. Използвате ли най-новия PyMC3? Получавам само NameError: името 'defs' не е дефинирано, което има смисъл, защото не е дефинирано.   -  person John Salvatier    schedule 13.06.2015
comment
Също така, освен ако нямате липсващи стойности или наистина ви е грижа за tau_att3 или tau_def3 (но не ги използвате), не смятам, че е необходимо да моделирате atts_star и defs_star с нормално разпределение, можете просто да използвате данните директно.   -  person John Salvatier    schedule 13.06.2015
comment
Имате ли версия на PyMC2, която работи?   -  person Abraham D Flaxman    schedule 14.06.2015
comment
Здравей @AbrahamDFlaxman, добавих кода PyMC2, благодаря за това.   -  person Peadar Coyle    schedule 14.06.2015


Отговори (3)


Ето моя превод на вашия модел PyMC2:

model = pm.Model()
with pm.Model() as model:
    # global model parameters
    home        = pm.Normal('home',      0, .0001)
    tau_att     = pm.Gamma('tau_att',   .1, .1)
    tau_def     = pm.Gamma('tau_def',   .1, .1)
    intercept   = pm.Normal('intercept', 0, .0001)

    # team-specific model parameters
    atts_star   = pm.Normal("atts_star", 
                           mu   =0,
                           tau  =tau_att, 
                           shape=num_teams)
    defs_star   = pm.Normal("defs_star", 
                           mu   =0,
                           tau  =tau_def,  
                           shape=num_teams)

    atts        = pm.Deterministic('atts', atts_star - tt.mean(atts_star))
    defs        = pm.Deterministic('defs', defs_star - tt.mean(defs_star))
    home_theta  = tt.exp(intercept + home + atts[home_team] + defs[away_team]
    away_theta  = tt.exp(intercept + atts[away_team] + defs[home_team])

    # likelihood of observed data
    home_points = pm.Poisson('home_points', mu=home_theta, observed=observed_home_goals)
    away_points = pm.Poisson('away_points', mu=away_theta, observed=observed_away_goals)

Голямата разлика, както я виждам, между изграждането на модел PyMC2 и 3 е, че целият бизнес с първоначалните стойности в PyMC2 не е включен в изграждането на модел в PyMC3. Той се изтласква в частта за монтаж на модела на кода.

Ето един бележник, който поставя този модел в контекст с вашите данни и някакъв подходящ код: http://nbviewer.ipython.org/gist/aflaxman/55e23195fe0a0b089103

person Abraham D Flaxman    schedule 15.06.2015
comment
Благодаря Абрахам. Ще добавя това към моя разговор за PyData в Лондон - но със сигурност ще ви насоча :). - person Peadar Coyle; 16.06.2015
comment
Супер, а можеш ли да изпратиш слайдовете или запис на разговор? Звучи интересно. - person Abraham D Flaxman; 17.06.2015
comment
Знаете, че това е доста старо, но се опитах да репликирам резултатите и Pymc3 завършва с много различни задници (напр. домашният коефициент е около 0,0). - person fsociety; 28.11.2016
comment
Внимание, има грешка в този код. Редът за home_theta трябва да гласи home_theta = tt.exp(intercept + home + atts[home_team] + defs[away_team] Без корекцията получавате различни резултати от тези в pymc2. Отне ми време да намеря това! Това вероятно обяснява и fsociety проблем. - person DonCristobal; 23.01.2018

Вашият модел се проваля, защото не можете да използвате функциите на NumPy на тензорите theano. По този начин

np.mean(atts_star3)

Ще ви даде грешка. Можете да премахнете atts_star3 = pm3.Normal("atts_star",...) и просто да използвате масива NumPy директно atts_star3 = x.

Не мисля, че трябва изрично да моделирате и tau_att3, tau_def3 или defs_star.

Като алтернатива, ако искате да запазите тези променливи, можете да замените np.mean с theano.tensor.mean, което трябва да работи.

person John Salvatier    schedule 14.06.2015
comment
Благодаря за отговора Джон. Опитах това и получих Observed RV can't work with int. Мисля, че този модел използва нормалното разпределение на atts_star3 и т.н. - тъй като е в документа, на който основах кода. Мисля, че ще трябва да направя малко рефакторинг на кода и ще видя какво ще се случи след това. - person Peadar Coyle; 15.06.2015
comment
Така че след като последвах съвета ви. Но сега получавам тази грешка. TypeError Traceback (most recent call last) <ipython-input-22-07dd9000673b> in <module>() 67 68 ---> 69 home_theta3 = pm3.Deterministic('regression', T.exp(intercept3 + atts3[away_team] + defs3[home_team])) 70 away_theta3 = pm3.Deterministic('regression', T.exp(intercept3 + atts3[away_team] + defs3[home_team])) 71 # Unknown model parameters TypeError: 'function' object is not subscriptable - person Peadar Coyle; 15.06.2015
comment
изглежда, че atts3 или defs2 всъщност е функция по някакъв начин. Може би сте изпълнили коментирания код по-горе? - person John Salvatier; 15.06.2015
comment
Да, когато коментирах този код и просто добавих mu себе си и той се задейства за мен. Ще го проуча малко по-късно днес. Но мисля, че работи като „хакерски“ пример за силата на PyMC3. Какво мислиш? - person Peadar Coyle; 16.06.2015

Така че направих това. Това не е директен порт на предишната ми версия, но ми дава отговор. Някой има ли отзиви?

import os
import math
import warnings
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pymc3 as pm3# I know folks are switching to "as pm" but I'm just not there yet
%matplotlib inline
import seaborn as sns
from IPython.core.pylabtools import figsize
import seaborn as sns
import theano.tensor as T
figsize(12, 12)
DATA_DIR = os.path.join(os.getcwd(), 'data/')
data_file = DATA_DIR + 'results_2014.csv'

df = pd.read_csv(data_file, sep=',')
# Or whatever it takes to get this into a data frame.
teams = df.home_team.unique()
teams = pd.DataFrame(teams, columns=['team'])
teams['i'] = teams.index
df = pd.merge(df, teams, left_on='home_team', right_on='team', how='left')
df = df.rename(columns = {'i': 'i_home'}).drop('team', 1)
df = pd.merge(df, teams, left_on='away_team', right_on='team', how='left')
df = df.rename(columns = {'i': 'i_away'}).drop('team', 1)
observed_home_goals = df.home_score.values
observed_away_goals = df.away_score.values
home_team = df.i_home.values
away_team = df.i_away.values
num_teams = len(df.i_home.drop_duplicates())
num_games = len(home_team)
g = df.groupby('i_away')
att_starting_points = np.log(g.away_score.mean())
g = df.groupby('i_home')
def_starting_points = -np.log(g.away_score.mean())

import theano.tensor as T
import pymc3 as pm3
#hyperpriors

'''
def atts3(atts_star3=atts_star3):
    atts3 = atts_star.copy()
    atts3 = atts3 - np.mean(atts_star)
    return atts3
def defs3(defs_star3=defs_star3):
    defs3 = defs_star3.copy()
    defs3 = defs3 - np.mean(defs_star3)
    return defs
    '''
model = pm3.Model()
with pm3.Model() as model:
    home3 = pm3.Normal('home', 0, .0001)
    tau_att3 = pm3.Gamma('tau_att', .1, .1)
    tau_def3 = pm3.Gamma('tau_def', .1, .1)
    intercept3 = pm3.Normal('intercept', 0, .0001)
    #team-specific parameters
    atts_star3 = pm3.Normal("atts_star", 
                        mu=0, 
                        tau=tau_att3, 
                        shape=num_teams, 
                        observed=att_starting_points.values)
    defs_star3 = pm3.Normal("defs_star", 
                        mu=0, 
                        tau=tau_def3, 
                        shape=num_teams, 
                        observed=def_starting_points.values) 


    #home_theta3 = atts3 + defs3
    #away_theta3 = atts3 + defs3
    # Unknown model parameters
    home_points3 = pm3.Poisson('home_points', mu=1, observed=observed_home_goals)
    away_points3 = pm3.Poisson('away_points', mu=1, observed=observed_away_goals)
    start = pm3.find_MAP()
    step = pm3.NUTS(state=start)
    trace = pm3.sample(2000, step, start=start, progressbar=True)

    pm3.traceplot(trace)
person Peadar Coyle    schedule 15.06.2015
comment
Ще публикувам своя превод на вашия PyMC2 код, който е малко по-различен. - person Abraham D Flaxman; 15.06.2015
comment
Страхотно :) Ще се радвам да го видя. - person Peadar Coyle; 16.06.2015
comment
Приех твоята версия Ейбрахам. Моят не е добре написан :) - person Peadar Coyle; 16.06.2015