Análise das estatísticas dos times e
jogadores em Life
Jeferson Valadares
Idevan Gonçalves Freire Júnior
Reginaldo Valadares
Objetivos - Motivação
Extrair estatísticas a partir de páginas na Web
 Carrega-las como fatos em um BDD
 Completa-las com estatísticas derivadas
 Pre-processamento para mineração
 Estudo de caso:

• derivar a partir das estatísticas elementares padrões de
basquete (ex, pts, reb, ast etc.)
• estatísticas compostas medindo o desempenho global dos
jogadores e dos times
• Tendex básico = (pts + reb + ast + stl + blk - (FGA-FGM) (FTA-FTM) -TO)) / game_num
• Tendex normalizados por vários fatores
Normalizações de Tendex
Tendex básico de time
 Tendex de jogador normalizado por ritmo de jogo
 Tendex de jogador normalizado por ritmo de jogo
e minutos jogados

Problemas encontrados durante a
implementação

Florid é uma ferramenta limitada:
• Falta conversão de strings para inteiros
• Falta cálculo com números reais
• Falta regras genéricas para decompor strings em
substrings

predicado built-in substring pode ser chamado apenas com 2
variáveis instanciadas
• Expressões regulares para fazer parsing não permitem
analisar padrões sensíveis ao contexto

Solução: pipeline de FLORID com LIFE
Criação de BD’s dos times

Extrair estruturas das home-pages:
teamstatsoff:page =
"http://www.di.ufpe.br/~streak/espn.sportszone.com/nba/
statistics/1998/teamstatoff.html".
teamstatsdef:page =
"http://www.di.ufpe.br/~streak/espn.sportszone.com/nba/
statistics/1998/teamstatdef.html".

Modelar a Web
page::url.
X.get[] :- X:page.
Criação de BD’s dos times

Criando os objetos (times)
atl:time[nome->"Atlanta"].
bos:time[nome->"Boston"].
...
was:time[nome->"Washington"].

Buscando as tabelas
T:tb :match(teamstatsoff.get,"<pre>.\(.*\n\)*</pre>","",_tmp),
match(_tmp,"\(.*[0-9][0-9].*\)","",T).

Exemplo
<pre><b>Team
LA Lakers
Minnesota
G Fgm-Fga
PCT 3pm-3pa PCT Ftm-Fta
PCT AVG</b>
82 3146-6536 .481 497-1418 .350 1863-2741 .680 105.5
82 3157-6844 .461 303-873 .347 1673-2263 .739 101.1
Criação de BD’s dos times

Carregando a base de dados
Time:time[ast->T] :- _tmp:tb,
strcat("\(.*", Time.nome, Strtmp),
strcat(Strtmp, "\)[ ]*[0-9]*-[0-9]*[ ]*\([0-9]*\)[ ]*\([09]*\)[ ]*\([0-9]*\)[ ]*\([0-9]*\)[ ]*\([0-9]*\)\(.*\)",
Str),match(_tmp, Str, "\3", T).

Analogamente para pts,reb, blk, fga, fgm, fta, ftm, fto
Demo ao vivo
Answer to query :
?- TIME:time[nome -> NOME; fgm -> FGM; fga -> FGA; ftm -> FTM;
fta -> FTA; pts -> PTS].
TIME/atl
PTS/"95.8"
FTA/"2312"
FTM/"1749"
FGA/"6352"
FGM/"2887"
NOME/"Atlanta"
TIME/bos
PTS/"95.9"
FTA/"1964"
FTM/"1425"
FGA/"6924"
FGM/"3012"
NOME/"Boston”
...
TIME/was
PTS/"97.2"
FTA/"2156"
FTM/"1489"
FGA/"6811"
FGM/"3080"
NOME/"Washington"
Criação de BD’s dos jogadores

Criando os objetos (times)
atl:time[nome->"Atlanta"].
bos:time[nome->"Boston"].
...
was:time[nome->"Washington"].

Buscando as home-pages:
atl[webpage ->
"http://www.di.ufpe.br/~streak/espn.sportszone.com/nba/
teamstats/atl.html".
atl.webpage:url.
Criação de BD’s dos jogadores

Buscando as tabelas
T:tb :- match(atl.webpage.get,"<td align
=\"left\">\n<pre>\(.*\n\)*</pre>","", T).
U:tb2:- match(T:tb, "\(.*\n\)*", "", U).
V:tb3 :- match(U:tb2,"\([A-Z][a-z]* [a-zA-Z]*\)
*\([0-9]*\)[---]\([0-9]*\)\(.*\)","",V).
V:tb4 :- match(U:tb2,"\([A-Z][a-z']* [a-zA-Z']*\)
*\([0-9][0-9]?\) *.*","",V).

Exemplo:
<pre><b>
Rebounds
G Min PPG RPG APG Off- Def- Tot AST Stl BLK To
PF</b></pre></font><br><img src="/img/blueline.gif" width="465" height="1"
vspace=0><br clear=all>
</td></tr>
<tr><td align="left">
<pre>Shaquille Oneal 60 2175 28.3 11.4 2.4 208- 473- 681 142 39 144 175 193
Eddie Jones
80 2910 16.9 3.8 3.1 85- 217- 302 246 160 55 146 164
Kobe Bryant
79 2056 15.4 3.1 2.5 79- 163- 242 199 74 39 157 180
Criação de BD’s dos jogadores

Carregando a base de dados
Time[jogador ->> {X}; jogador@(X,gp) -> Y] :_T1:tb3, _T2:tb4, Time:time,
match(_T1:tb3,"\([A-Z][a-z]* [a-zA-Z]*\) *\([0-9][09]*\).\([0-9][0-9]*\)","\1",X),
match(X,"\([A-Z][a-zA-Z]*\) *\([a-zA-Z]*\)","\1”,X1),
strcat(X1,".*",X3),
match(X,"\([A-Z][a-zA-Z]*\) *\([a-zA-Z]*\)","\2",X2),
strcat(X2," .*",X4), strcat(X3,X4,X5),
match(_T2,X5,"",Y1),
match(Y1,"[a-zA-Z'] [a-zA-Z]* *\([0-9][0-9]*\) *\([09][0-9]*\) *\([0-9][0-9]*.[0-9]\) *\([0-9][0-9]*.[09]\) *\([0-9][0-9]*.[0-9]\)","\1",Y).
Demo ao vivo
Answer to query : ?- Time[jogador@(X,nome) ->
NOME; jogador@(X,fgm) -> FGM; jogador@(X,fga) ->
FGA; jogador@(X,ftm) -> FTM; jogador@(X,fta) ->
FTA; jogador@(X,pts) -> PTS].
...
Time/van
FTM/"223"
...
X/"Reeves "
FGA/"942"
PTS/"1209"
FTA/"316"
FGM/"493"
NOME/"Reeves "
Leitura de arquivos em Life

Arquivo de entrada (nba1) no formato:
atl:time[nome -> "Atlanta"; fgm -> "2887"; fga -> "6352"; ftm ->
"1749”].
bos:time[nome -> "Boston"; fgm -> "3012"; fga -> "6924"; ftm ->
"1425”].

Primeiro passo do programa: (troca de caracteres)
clear1 :-X=system("cat nba1 | tr \\- \\= | tr '\[' '\(' | tr '\]' '\)' | tr
'\;' '\,' > nba1x").

Arquivo resultado (nba1x):
atl:time(nome => "Atlanta", fgm => "2887", fga => "6352", ftm =>
"1749”).
bos:time(nome => "Boston", fgm => "3012", fga => "6924", ftm =>
"1425”).
Transformando o arquivo de entrada
num conjunto de declarações






Ler o arquivo resultado linha por linha
Filtrar os elementos indesejados da linha
Escrever linha no arquivo nba1y
Dados de entrada já podem ser lidos (load) e entendidos pelo
Life
Calcular Tendex de cada time
Mostrar a lista em ordem decrescente
Código - proc_file
proc_file :- open_in(nba1x, In), open_out(nba1y, Out),
repeat,
get_line(Line),
( Line = end_of_file,
close(In),
close(Out),
!
;
(( substr(Line,4,1)=":",
Line1 <- filter(Line),
write(substr(Line1,5,strlen(Line1)-4)),nl)),
fail
).
Código - get_line
get_line(Line) :- get(Char),get_rest(Char,"", Line).
get_rest(Char,Line,R):( Char = end_of_file, nl,
R <- Char, !
;
Char = 10, R=Line, !
;
Line1 = strcon(Line,chr(Char)),
get(Char1),
get_rest(Char1,Line1,R)).
Código - filter(S)
filter("") -> "".
filter(S) -> R | H = hds(S), T = tls(S), H1 = hds(T),
(( digit(H1), asc(H ) = 34, R=filter(T), !
; digit(H) , asc(H1) = 34,
R=strcon(H,filter(tls(T))), !
; R=strcon(H,filter(T)), !
)).
Resultado da aplicação de filter(S):
atl:time(nome => "Atlanta", fgm => "2887", fga => "6352", ftm => "1749”).
time(nome => "Atlanta", fgm => 2887, fga => 6352, ftm => 1749).
Cálculo do Tendex dos times
dynamic(timex)?
toTendex :T = time, T , T =time(fga=>FGA, reb=>REB, nome=>N),FGA\===@, REB:==@,
T1=time,T1,T1=time(fga=>FGA1,reb=>REB1,nome=>N),REB1\===@,FGA1:==@,
TENDEX = T.pts+T1.reb+T1.ast+T1.stl+T1.blk-(T.fga-T.fgm)-(T.fta-T.ftm)T1.to,
assert(timex(nome=>N, tendex => TENDEX)),
fail.
toTendex.
Ordenação dos times
import("lists")?
sort(L,F) -> gen_quicksort (L, order => F).
sort_func(@(tendex=>X), @(tendex=>Y)) -> X>Y.
bagTendex(B) :- X=timex, B=bagof(X,X).
geraTendex :- bagTendex(X), X4=sort(X,sort_func),
write("Lista por ordem decrescente de Tendex"), nl, nl,
wl(X4),nl.
wl([]) :- !.
wl([X|Xs]) :- write(X),nl,wl(Xs). .
Execução
>teams?
Lista em ordem decrescente:
team(nome => Utah,tendex => 1618)
team(nome => Phoenix,tendex => 1554.6)
team(nome => LA Lakers,tendex => 1430.5)
team(nome => San Antonio,tendex => 1355.5)
team(nome => Chicago,tendex => 1345.7)
team(nome => Minnesota,tendex => 1312.1)
team(nome => Seattle,tendex => 1264.6)
team(nome => Indiana,tendex => 1240)
Download

nba-db-from-web.flp