SlideShare a Scribd company logo
1 of 20
Download to read offline
scipy	
  e	
  rpy	
  per	
  l'analisi	
  
degli	
  acquisti	
  della	
  
pubblica	
  amministrazione	
  
Francesco	
  Cavazzana	
  
Input	
  -­‐>	
  Output	
  
28.000	
  file	
  XML 	
   	
   	
  	
  	
  	
  	
  	
  à	
  2.000	
  righe	
  per	
  50	
  colonne	
  di	
  analisi	
  +	
  4.000	
  grafici	
  	
  	
  
Tutti	
  i	
  dati	
  sugli	
  acquisti	
  pubblici	
  devono	
  
essere	
  pubblici	
  –	
  Legge	
  190/2012	
  
Ê  Entro	
  il	
  31	
  gennaio	
  di	
  ogni	
  anno,	
  tali	
  informazioni,	
  
relativamente	
  all'anno	
  precedente,	
  sono	
  pubblicate	
  in	
  
Ê  	
  tabelle	
  riassuntive	
  rese	
  liberamente	
  scaricabili	
  
Ê  	
  in	
  un	
  formato	
  digitale	
  standard	
  aperto	
  	
  
Ê  che	
  consenta	
  di	
  analizzare	
  e	
  rielaborare,	
  anche	
  a	
  fini	
  statistici,	
  
i	
  dati	
  informatici.	
  	
  
Ê  L’Autorità	
  competente	
  (AVCP	
  –	
  ANAC)	
  ha	
  stabilito	
  il	
  
formato:	
  
Ê  http://dati.avcp.it/schema/datasetAppaltiL190.xsd	
  	
  
Ê  http://dati.avcp.it/schema/datasetIndiceAppaltiL190.xsd	
  
Ê  http://dati.avcp.it/schema/TypesL190.xsd	
  	
  
I	
  dati	
  sono	
  disponibili	
  sui	
  siti	
  web	
  di	
  
ciascun	
  ente	
  pubblico	
  
Principali	
  dati	
  disponibili	
  
Ê  Descrizione	
  acquisto	
  
Ê  Data	
  inizio	
  e	
  fine	
  fornitura	
  
Ê  Importo	
  aggiudicato	
  e	
  importo	
  liquidato	
  
Ê  Tipo	
  di	
  procedura	
  utilizzata	
  
Ê  Aggiudicatario	
  
Ê  Elenco	
  dei	
  partecipanti	
  alla	
  gara	
  
Ê  Ogni	
  acquisto	
  dal	
  1/12/12	
  indipendentemente	
  
dall’importo	
  
Possibili	
  utilizzi	
  di	
  questi	
  dati	
  
Ê  Trasparenza	
  
Ê  Anticorruzione	
  
ma	
  anche	
  
Ê  Analisi	
  di	
  benchmark	
  per	
  le	
  amministrazioni	
  pubbliche	
  
Ê  Analisi	
  di	
  mercato	
  
Ê  Monitoraggio	
  della	
  concorrenza	
  
Ê  Individuazione	
  di	
  potenziali	
  clienti	
  (pubblici)	
  
	
  
Dati	
  analizzati	
  
Ê 42	
  università	
  	
  
Ê 7	
  comuni	
  	
  
Ê 2	
  anni	
  
Ê 28.634	
  file	
  XML	
  	
  
Ê 467.527	
  acquisti	
  
Ê 3.015.189.341,15	
  €	
  di	
  importo	
  totale	
  
Ê 68.138	
  aziende	
  partecipanti	
  	
  
Importazione	
  dei	
  dati	
  da	
  XML	
  
Ê  Genropy	
  Bag	
  
Ê  from	
  gnr.core.gnrbag	
  import	
  Bag	
  
Ê  b	
  =	
  Bag(xml_source_dati)	
  
Ê  b['legge190:pubblicazione.data.#0.cig']	
  
Ê  5835815AE0	
  
numpy,	
  il	
  75%	
  degli	
  acquisti	
  valgono	
  
meno	
  di	
  quanti	
  €	
  ?	
  
import numpy as np
# query su database -> oltre 230.000 righe di
risultato
importi = self.query_limiti(…)
x = np.array([float(r[0]) for r in importi])
result.append(('Numero acquisti', len(x))
result.append(('Totale aggiudicato’, x.sum()))
result.append(('min', x.min()))
result.append(('media', x.mean()))
result.append(('mediana, ’np.median(x)))
result.append(('deviazione standard’, x.std()))
result.append(('75%: <= ', np.percentile(x, 75)))
scipy.stats,	
  quanti	
  acquisti	
  ci	
  vogliono	
  per	
  
fare	
  l’80%	
  del	
  valore	
  speso?	
  	
  
totale = x.sum()
x = np.flipud(x)#ordino al contrario dal più grande al più piccolo
def sommeParziali():
somma = np.float(0)
for r in x:
somma += r
yield somma
iterable = sommeParziali()
somme = np.fromiter(iterable, np.float)
result.append(('',''))
result.append(('Concentrazione del valore', '_titolo_'))
result.append((‘80% del valore dato da % acquisti',
self.fmtNumber(st.percentileofscore(somme, totale * 0.8))))
Rendiamole	
  multiprocesso	
  
Ê  42	
  enti:	
  analizziamoli	
  in	
  parallelo	
  
pool = multiprocessing.Pool(multiprocessing.cpu_count(),
initAnalizzatore, (… parametri di init …))
analisi = pool.map(analisiUnGruppoUnAnno,
[(anno,un_ente_id) for un_ente_id in lista_enti])
Ê  L’analisi	
  dei	
  42	
  enti	
  è	
  indipendente	
  l’una	
  dall’altra	
  
Ê  I	
  dati	
  vengono	
  letti	
  dal	
  DB	
  parallelamente	
  da	
  ciascun	
  
processo	
  
Ê  I	
  tempi	
  di	
  analisi	
  vengono	
  effettivamente	
  divisi	
  per	
  il	
  numero	
  
di	
  processori	
  disponibili	
  (se	
  il	
  consumo	
  di	
  RAM	
  è	
  ragionevole)	
  
Come	
  mostriamo	
  gli	
  output?	
  
Ê import	
  xlsxwriter	
  
Ê Perché	
  un	
  foglio	
  di	
  calcolo	
  come	
  output?	
  
Ê è	
  facile	
  fare	
  ulteriori	
  analisi	
  al	
  volo	
  sugli	
  output	
  
Ê si	
  ottengono	
  facilmente	
  tabelle	
  e	
  grafici	
  per	
  
presentazioni	
  o	
  testi	
  	
  
Ê la	
  griglia	
  è	
  un	
  modo	
  logico	
  per	
  visualizzare	
  dati	
  
di	
  questo	
  tipo,	
  soprattutto	
  se	
  semilavorati	
  
Ê non	
  perdiamo	
  tempo	
  con	
  la	
  grafica,	
  ci	
  
interessano	
  i	
  numeri!	
  
I	
  grafici	
  facili	
  li	
  lasciamo	
  fare	
  ad	
  excel	
  
def writeGraficoTorta(self, f_strutt, row, col, value, i, data):
chart1 = self.workbook.add_chart({'type': 'pie'})
#Configure the series. Note the use of the list syntax to define ranges
chart1.add_series({
'name': value['grafico'],
'categories': [f_strutt.name, row - value['dati'], 0, row - 1, 0],
'values': [f_strutt.name, row - value['dati'], col, row - 1, col],
'data_labels': {'percentage': True} #, 'category':True}})
chart1.set_legend({'height': 0.9})
# Add a title.
chart1.set_title({'none': True})
# Set an Excel chart style. Colors with white outline and shadow.
chart1.set_style(10)
chart1.set_size({'width': 314, 'height': 250, 'x_offset':4, 'y_offset':4})
# Insert the chart into the worksheet (with an offset).
f_strutt.insert_chart(row, col, chart1)
f_strutt.set_row(row, 200)
I	
  grafici	
  difficili	
  li	
  facciamo	
  fare	
  ad	
  R	
  
jpeg(filename = "%(filename)s_DIM_NUM_plot”, width = 11, height = 7,
units = "cm", pointsize = 8, res=300, quality=50, bg = "white")
plot(x=data$numero, y=data$importo_tot, xlab="numero acquisti",
ylab="importo acquisti", col=data$cluster)
d1 <- subset(data, subset=c(data$numero > mean(data$numero) |
data$importo_tot > mean(data$importo_tot)))
textxy(d1$numero, d1$importo_tot, d1$sigla)
abline(v=mean(data$numero))
abline(h=mean(data$importo_tot))
dev.off()
Appunto	
  R…	
  ma	
  da	
  python!	
  
import rpy2.robjects as robjects
r_code = ” … il codice R lo abbiamo visto prima … “
robjects.r(r_code)
result.append(('Plot numero / importo acquisti',{'tipo':'immagine’,
'filename':connection_params['filename']+'_DIM_NUM_plot'}))
result.append(('Numero università per cluster',str(robjects.r(’cluster$size'))))
Ê  I	
  dati	
  in	
  input	
  sono	
  presi	
  da	
  R	
  direttamente	
  dal	
  database	
  -­‐>	
  si	
  evita	
  la	
  
serializzazione	
  dei	
  dati	
  pesanti	
  
Ê  I	
  grafici	
  in	
  output	
  sono	
  salvati	
  in	
  path	
  conosciuti	
  da	
  entrambi	
  i	
  
linguaggi	
  
Ê  Per	
  casi	
  non	
  troppo	
  complessi	
  il	
  passaggio	
  dati	
  tra	
  i	
  due	
  linguaggi	
  	
  è	
  
totalmente	
  trasparente	
  
Altre	
  cose	
  difficili	
  in	
  R:	
  le	
  regressioni	
  
drv <- dbDriver("PostgreSQL")
con <- dbConnect(drv, dbname="%(database)s", user="%(user)s”)
rs <- dbSendQuery(con, "%(query)s")
data <- fetch(rs,n=-1)
data$area_geografica<-factor(data$area_geografica)
data$area_geografica<-relevel(data$area_geografica, ref="N”)
m1geo <- lm(numero~area_geografica, data=data)
plot(x=data$area_geografica, y=data$numero, xlab='Area geografica’,
ylab='Numero acquisti’)
R…	
  magia	
  nera!	
  
rs <- dbSendQuery(con, "%(query)s")
data <- fetch(rs,n=-1)
data$imp_doc <- data$importo_tot / data$num_docenti
data$dim_docenti_cat_2 <- cut(data$num_docenti,
breaks=c(0,500,1000,1500,4000), dig.lab=10)
paste(c('milano', 'varese', 'como'), '2014', sep=' - ')
[1] "milano - 2014" "varese - 2014" "como - 2014"
Ê  Questa	
  divisione	
  non	
  è	
  fra	
  due	
  numeri…	
  ma	
  fra	
  decine	
  (o	
  milioni)	
  di	
  
numeri	
  
Ê  Prendiamo	
  il	
  numero	
  di	
  docenti	
  di	
  ciascuna	
  università	
  e	
  lo	
  
trasformiamo	
  in	
  un	
  fattore	
  a	
  4	
  livelli,	
  in	
  modo	
  da	
  ottenere	
  quattro	
  
gruppi	
  di	
  università	
  divisi	
  per	
  classe	
  dimensionale	
  	
  
Ê  Altro	
  esempio	
  di	
  come	
  R	
  ragioni	
  sempre	
  magicamente	
  per	
  vettori	
  
Cose	
  ancora	
  più	
  difficili	
  in	
  R:	
  clustering	
  
dataClustering <- subset(dataK, select=c('i_2’,'i_40’,'i_207’,'i_inf'))
rownames(dataClustering) <- dataK$codice_fiscale
dataClustering[is.na(dataClustering)==T]<-0
k_cluster <- kmeans(dataClustering, 3)
d1 <- data.frame(cluster = k_cluster$cluster,
codice_fiscale=names(k_cluster$cluster))
data <- merge(data, d1, by='codice_fiscale')
data$cluster<-factor(data$cluster)
plot(dataClustering, col=data$cluster)
Concludendo	
  
Rispetto	
  a	
  fare	
  l’analisi	
  in	
  excel,	
  il	
  vantaggio	
  è	
  che	
  si	
  può…	
  
Ê  …	
  ripetere	
  le	
  analisi	
  decine	
  di	
  volte	
  con	
  poco	
  sforzo,	
  
cambiando	
  qualche	
  ipotesi	
  o	
  qualche	
  tipo	
  di	
  analisi	
  
Ê  …	
  aggiungere	
  dati	
  (es.	
  un	
  anno	
  di	
  analisi	
  in	
  più)	
  senza	
  
nessuno	
  sforzo	
  
Ê  …	
  analizzare	
  centinaia	
  di	
  migliaia	
  o	
  milioni	
  di	
  righe	
  
Ê  …	
  interagire	
  con	
  SQL	
  senza	
  lavoro	
  manuale	
  (una	
  
elaborazione	
  di	
  analisi	
  può	
  richiedere	
  decine	
  di	
  query)	
  
Ê  …	
  cambiare	
  quando	
  si	
  vuole	
  l’ambito	
  delle	
  analisi	
  (es.	
  
vediamo	
  solo	
  gli	
  acquisti	
  <	
  1.000	
  €	
  nelle	
  regioni	
  del	
  nord)	
  
Grazie	
  
	
  
	
  
francesco@cavazzana.it	
  

More Related Content

Viewers also liked

Wykorzystanie wsparcia powietrznego
Wykorzystanie wsparcia powietrznegoWykorzystanie wsparcia powietrznego
Wykorzystanie wsparcia powietrznegogeneral-la
 
TCCC - Tactial Combat Casualty Care
TCCC - Tactial Combat Casualty CareTCCC - Tactial Combat Casualty Care
TCCC - Tactial Combat Casualty Caregeneral-la
 
Gestion paquetes NuGet con Visual Studio Team Services y MyGet
Gestion paquetes NuGet con Visual Studio Team Services y MyGetGestion paquetes NuGet con Visual Studio Team Services y MyGet
Gestion paquetes NuGet con Visual Studio Team Services y MyGetLuis Fraile
 
Next Generation Software Engineers Program
Next Generation Software Engineers ProgramNext Generation Software Engineers Program
Next Generation Software Engineers ProgramAbobakr Shahrah
 
ElleBj - Body Jewels
ElleBj - Body JewelsElleBj - Body Jewels
ElleBj - Body Jewelssaralugli
 
Najsexi baby na internete
Najsexi baby na interneteNajsexi baby na internete
Najsexi baby na internetePetkaHuskova
 
Nocturnal Enuresis in Psychiatry
Nocturnal Enuresis in PsychiatryNocturnal Enuresis in Psychiatry
Nocturnal Enuresis in PsychiatryKavindya Fernando
 
Agiles 2009 - Power Workshops: Kick-starting your Agile Project - Joke Vandem...
Agiles 2009 - Power Workshops: Kick-starting your Agile Project - Joke Vandem...Agiles 2009 - Power Workshops: Kick-starting your Agile Project - Joke Vandem...
Agiles 2009 - Power Workshops: Kick-starting your Agile Project - Joke Vandem...Agiles2009
 

Viewers also liked (11)

Wykorzystanie wsparcia powietrznego
Wykorzystanie wsparcia powietrznegoWykorzystanie wsparcia powietrznego
Wykorzystanie wsparcia powietrznego
 
DevOps is a ReOrg
DevOps is a ReOrgDevOps is a ReOrg
DevOps is a ReOrg
 
TCCC - Tactial Combat Casualty Care
TCCC - Tactial Combat Casualty CareTCCC - Tactial Combat Casualty Care
TCCC - Tactial Combat Casualty Care
 
Investor deck
Investor deckInvestor deck
Investor deck
 
Gestion paquetes NuGet con Visual Studio Team Services y MyGet
Gestion paquetes NuGet con Visual Studio Team Services y MyGetGestion paquetes NuGet con Visual Studio Team Services y MyGet
Gestion paquetes NuGet con Visual Studio Team Services y MyGet
 
Next Generation Software Engineers Program
Next Generation Software Engineers ProgramNext Generation Software Engineers Program
Next Generation Software Engineers Program
 
ElleBj - Body Jewels
ElleBj - Body JewelsElleBj - Body Jewels
ElleBj - Body Jewels
 
Ss presentation!
Ss presentation!Ss presentation!
Ss presentation!
 
Najsexi baby na internete
Najsexi baby na interneteNajsexi baby na internete
Najsexi baby na internete
 
Nocturnal Enuresis in Psychiatry
Nocturnal Enuresis in PsychiatryNocturnal Enuresis in Psychiatry
Nocturnal Enuresis in Psychiatry
 
Agiles 2009 - Power Workshops: Kick-starting your Agile Project - Joke Vandem...
Agiles 2009 - Power Workshops: Kick-starting your Agile Project - Joke Vandem...Agiles 2009 - Power Workshops: Kick-starting your Agile Project - Joke Vandem...
Agiles 2009 - Power Workshops: Kick-starting your Agile Project - Joke Vandem...
 

Similar to scipy e rpy per l'analisi degli acquisti della pubblica amministrazione

Back to Basics, webinar 5: Introduzione ad Aggregation Framework
Back to Basics, webinar 5: Introduzione ad Aggregation FrameworkBack to Basics, webinar 5: Introduzione ad Aggregation Framework
Back to Basics, webinar 5: Introduzione ad Aggregation FrameworkMongoDB
 
Sintesi automatica di una metrica di similarità tra stringhe tramite tecniche...
Sintesi automatica di una metrica di similarità tra stringhe tramite tecniche...Sintesi automatica di una metrica di similarità tra stringhe tramite tecniche...
Sintesi automatica di una metrica di similarità tra stringhe tramite tecniche...mfurlanetto
 
Web advanced-11-d3 js
Web advanced-11-d3 jsWeb advanced-11-d3 js
Web advanced-11-d3 jsStudiabo
 
7. MATLAB - Parte 2 (IO, cicli, funzioni).pdf
7. MATLAB - Parte 2 (IO, cicli, funzioni).pdf7. MATLAB - Parte 2 (IO, cicli, funzioni).pdf
7. MATLAB - Parte 2 (IO, cicli, funzioni).pdfPasqualeRuocco5
 
Programmazione strutturata
Programmazione strutturataProgrammazione strutturata
Programmazione strutturataEmilia Calzetta
 
Strutture dati 06-dataframe
Strutture dati 06-dataframeStrutture dati 06-dataframe
Strutture dati 06-dataframeStudiabo
 
Lezione 8 (12 marzo 2012)
Lezione 8 (12 marzo 2012)Lezione 8 (12 marzo 2012)
Lezione 8 (12 marzo 2012)STELITANO
 
Data mining 06-dataframe
Data mining 06-dataframeData mining 06-dataframe
Data mining 06-dataframeStudiabo
 
Algoritmi e Programmazione Avanzata - Esercizi propedeutici
Algoritmi e Programmazione Avanzata - Esercizi propedeuticiAlgoritmi e Programmazione Avanzata - Esercizi propedeutici
Algoritmi e Programmazione Avanzata - Esercizi propedeuticiSergio Porcu
 
Python advanced 01-numpypandas
Python advanced 01-numpypandasPython advanced 01-numpypandas
Python advanced 01-numpypandasStudiabo
 
Python advanced 01-numpypandas
Python advanced 01-numpypandasPython advanced 01-numpypandas
Python advanced 01-numpypandasStudiabo
 
Javascript - 8 | WebMaster & WebDesigner
Javascript - 8 | WebMaster & WebDesignerJavascript - 8 | WebMaster & WebDesigner
Javascript - 8 | WebMaster & WebDesignerMatteo Magni
 
Strutture dati 05-numpypandas
Strutture dati 05-numpypandasStrutture dati 05-numpypandas
Strutture dati 05-numpypandasStudiabo
 

Similar to scipy e rpy per l'analisi degli acquisti della pubblica amministrazione (20)

R Graphics
R GraphicsR Graphics
R Graphics
 
Metodo di Newton
Metodo di NewtonMetodo di Newton
Metodo di Newton
 
Back to Basics, webinar 5: Introduzione ad Aggregation Framework
Back to Basics, webinar 5: Introduzione ad Aggregation FrameworkBack to Basics, webinar 5: Introduzione ad Aggregation Framework
Back to Basics, webinar 5: Introduzione ad Aggregation Framework
 
Sintesi automatica di una metrica di similarità tra stringhe tramite tecniche...
Sintesi automatica di una metrica di similarità tra stringhe tramite tecniche...Sintesi automatica di una metrica di similarità tra stringhe tramite tecniche...
Sintesi automatica di una metrica di similarità tra stringhe tramite tecniche...
 
Web advanced-11-d3 js
Web advanced-11-d3 jsWeb advanced-11-d3 js
Web advanced-11-d3 js
 
R Vectors
R VectorsR Vectors
R Vectors
 
Tutorial Matlab 2009
Tutorial Matlab 2009Tutorial Matlab 2009
Tutorial Matlab 2009
 
7. MATLAB - Parte 2 (IO, cicli, funzioni).pdf
7. MATLAB - Parte 2 (IO, cicli, funzioni).pdf7. MATLAB - Parte 2 (IO, cicli, funzioni).pdf
7. MATLAB - Parte 2 (IO, cicli, funzioni).pdf
 
Programmazione strutturata
Programmazione strutturataProgrammazione strutturata
Programmazione strutturata
 
Strutture dati 06-dataframe
Strutture dati 06-dataframeStrutture dati 06-dataframe
Strutture dati 06-dataframe
 
Riepilogo Java C/C++
Riepilogo Java C/C++Riepilogo Java C/C++
Riepilogo Java C/C++
 
Lezione 8 (12 marzo 2012)
Lezione 8 (12 marzo 2012)Lezione 8 (12 marzo 2012)
Lezione 8 (12 marzo 2012)
 
Data mining 06-dataframe
Data mining 06-dataframeData mining 06-dataframe
Data mining 06-dataframe
 
Array
ArrayArray
Array
 
Basi Di Dati 03
Basi Di Dati 03Basi Di Dati 03
Basi Di Dati 03
 
Algoritmi e Programmazione Avanzata - Esercizi propedeutici
Algoritmi e Programmazione Avanzata - Esercizi propedeuticiAlgoritmi e Programmazione Avanzata - Esercizi propedeutici
Algoritmi e Programmazione Avanzata - Esercizi propedeutici
 
Python advanced 01-numpypandas
Python advanced 01-numpypandasPython advanced 01-numpypandas
Python advanced 01-numpypandas
 
Python advanced 01-numpypandas
Python advanced 01-numpypandasPython advanced 01-numpypandas
Python advanced 01-numpypandas
 
Javascript - 8 | WebMaster & WebDesigner
Javascript - 8 | WebMaster & WebDesignerJavascript - 8 | WebMaster & WebDesigner
Javascript - 8 | WebMaster & WebDesigner
 
Strutture dati 05-numpypandas
Strutture dati 05-numpypandasStrutture dati 05-numpypandas
Strutture dati 05-numpypandas
 

scipy e rpy per l'analisi degli acquisti della pubblica amministrazione

  • 1. scipy  e  rpy  per  l'analisi   degli  acquisti  della   pubblica  amministrazione   Francesco  Cavazzana  
  • 2. Input  -­‐>  Output   28.000  file  XML                à  2.000  righe  per  50  colonne  di  analisi  +  4.000  grafici      
  • 3. Tutti  i  dati  sugli  acquisti  pubblici  devono   essere  pubblici  –  Legge  190/2012   Ê  Entro  il  31  gennaio  di  ogni  anno,  tali  informazioni,   relativamente  all'anno  precedente,  sono  pubblicate  in   Ê   tabelle  riassuntive  rese  liberamente  scaricabili   Ê   in  un  formato  digitale  standard  aperto     Ê  che  consenta  di  analizzare  e  rielaborare,  anche  a  fini  statistici,   i  dati  informatici.     Ê  L’Autorità  competente  (AVCP  –  ANAC)  ha  stabilito  il   formato:   Ê  http://dati.avcp.it/schema/datasetAppaltiL190.xsd     Ê  http://dati.avcp.it/schema/datasetIndiceAppaltiL190.xsd   Ê  http://dati.avcp.it/schema/TypesL190.xsd    
  • 4. I  dati  sono  disponibili  sui  siti  web  di   ciascun  ente  pubblico  
  • 5. Principali  dati  disponibili   Ê  Descrizione  acquisto   Ê  Data  inizio  e  fine  fornitura   Ê  Importo  aggiudicato  e  importo  liquidato   Ê  Tipo  di  procedura  utilizzata   Ê  Aggiudicatario   Ê  Elenco  dei  partecipanti  alla  gara   Ê  Ogni  acquisto  dal  1/12/12  indipendentemente   dall’importo  
  • 6. Possibili  utilizzi  di  questi  dati   Ê  Trasparenza   Ê  Anticorruzione   ma  anche   Ê  Analisi  di  benchmark  per  le  amministrazioni  pubbliche   Ê  Analisi  di  mercato   Ê  Monitoraggio  della  concorrenza   Ê  Individuazione  di  potenziali  clienti  (pubblici)    
  • 7. Dati  analizzati   Ê 42  università     Ê 7  comuni     Ê 2  anni   Ê 28.634  file  XML     Ê 467.527  acquisti   Ê 3.015.189.341,15  €  di  importo  totale   Ê 68.138  aziende  partecipanti    
  • 8. Importazione  dei  dati  da  XML   Ê  Genropy  Bag   Ê  from  gnr.core.gnrbag  import  Bag   Ê  b  =  Bag(xml_source_dati)   Ê  b['legge190:pubblicazione.data.#0.cig']   Ê  5835815AE0  
  • 9. numpy,  il  75%  degli  acquisti  valgono   meno  di  quanti  €  ?   import numpy as np # query su database -> oltre 230.000 righe di risultato importi = self.query_limiti(…) x = np.array([float(r[0]) for r in importi]) result.append(('Numero acquisti', len(x)) result.append(('Totale aggiudicato’, x.sum())) result.append(('min', x.min())) result.append(('media', x.mean())) result.append(('mediana, ’np.median(x))) result.append(('deviazione standard’, x.std())) result.append(('75%: <= ', np.percentile(x, 75)))
  • 10. scipy.stats,  quanti  acquisti  ci  vogliono  per   fare  l’80%  del  valore  speso?     totale = x.sum() x = np.flipud(x)#ordino al contrario dal più grande al più piccolo def sommeParziali(): somma = np.float(0) for r in x: somma += r yield somma iterable = sommeParziali() somme = np.fromiter(iterable, np.float) result.append(('','')) result.append(('Concentrazione del valore', '_titolo_')) result.append((‘80% del valore dato da % acquisti', self.fmtNumber(st.percentileofscore(somme, totale * 0.8))))
  • 11. Rendiamole  multiprocesso   Ê  42  enti:  analizziamoli  in  parallelo   pool = multiprocessing.Pool(multiprocessing.cpu_count(), initAnalizzatore, (… parametri di init …)) analisi = pool.map(analisiUnGruppoUnAnno, [(anno,un_ente_id) for un_ente_id in lista_enti]) Ê  L’analisi  dei  42  enti  è  indipendente  l’una  dall’altra   Ê  I  dati  vengono  letti  dal  DB  parallelamente  da  ciascun   processo   Ê  I  tempi  di  analisi  vengono  effettivamente  divisi  per  il  numero   di  processori  disponibili  (se  il  consumo  di  RAM  è  ragionevole)  
  • 12. Come  mostriamo  gli  output?   Ê import  xlsxwriter   Ê Perché  un  foglio  di  calcolo  come  output?   Ê è  facile  fare  ulteriori  analisi  al  volo  sugli  output   Ê si  ottengono  facilmente  tabelle  e  grafici  per   presentazioni  o  testi     Ê la  griglia  è  un  modo  logico  per  visualizzare  dati   di  questo  tipo,  soprattutto  se  semilavorati   Ê non  perdiamo  tempo  con  la  grafica,  ci   interessano  i  numeri!  
  • 13. I  grafici  facili  li  lasciamo  fare  ad  excel   def writeGraficoTorta(self, f_strutt, row, col, value, i, data): chart1 = self.workbook.add_chart({'type': 'pie'}) #Configure the series. Note the use of the list syntax to define ranges chart1.add_series({ 'name': value['grafico'], 'categories': [f_strutt.name, row - value['dati'], 0, row - 1, 0], 'values': [f_strutt.name, row - value['dati'], col, row - 1, col], 'data_labels': {'percentage': True} #, 'category':True}}) chart1.set_legend({'height': 0.9}) # Add a title. chart1.set_title({'none': True}) # Set an Excel chart style. Colors with white outline and shadow. chart1.set_style(10) chart1.set_size({'width': 314, 'height': 250, 'x_offset':4, 'y_offset':4}) # Insert the chart into the worksheet (with an offset). f_strutt.insert_chart(row, col, chart1) f_strutt.set_row(row, 200)
  • 14. I  grafici  difficili  li  facciamo  fare  ad  R   jpeg(filename = "%(filename)s_DIM_NUM_plot”, width = 11, height = 7, units = "cm", pointsize = 8, res=300, quality=50, bg = "white") plot(x=data$numero, y=data$importo_tot, xlab="numero acquisti", ylab="importo acquisti", col=data$cluster) d1 <- subset(data, subset=c(data$numero > mean(data$numero) | data$importo_tot > mean(data$importo_tot))) textxy(d1$numero, d1$importo_tot, d1$sigla) abline(v=mean(data$numero)) abline(h=mean(data$importo_tot)) dev.off()
  • 15. Appunto  R…  ma  da  python!   import rpy2.robjects as robjects r_code = ” … il codice R lo abbiamo visto prima … “ robjects.r(r_code) result.append(('Plot numero / importo acquisti',{'tipo':'immagine’, 'filename':connection_params['filename']+'_DIM_NUM_plot'})) result.append(('Numero università per cluster',str(robjects.r(’cluster$size')))) Ê  I  dati  in  input  sono  presi  da  R  direttamente  dal  database  -­‐>  si  evita  la   serializzazione  dei  dati  pesanti   Ê  I  grafici  in  output  sono  salvati  in  path  conosciuti  da  entrambi  i   linguaggi   Ê  Per  casi  non  troppo  complessi  il  passaggio  dati  tra  i  due  linguaggi    è   totalmente  trasparente  
  • 16. Altre  cose  difficili  in  R:  le  regressioni   drv <- dbDriver("PostgreSQL") con <- dbConnect(drv, dbname="%(database)s", user="%(user)s”) rs <- dbSendQuery(con, "%(query)s") data <- fetch(rs,n=-1) data$area_geografica<-factor(data$area_geografica) data$area_geografica<-relevel(data$area_geografica, ref="N”) m1geo <- lm(numero~area_geografica, data=data) plot(x=data$area_geografica, y=data$numero, xlab='Area geografica’, ylab='Numero acquisti’)
  • 17. R…  magia  nera!   rs <- dbSendQuery(con, "%(query)s") data <- fetch(rs,n=-1) data$imp_doc <- data$importo_tot / data$num_docenti data$dim_docenti_cat_2 <- cut(data$num_docenti, breaks=c(0,500,1000,1500,4000), dig.lab=10) paste(c('milano', 'varese', 'como'), '2014', sep=' - ') [1] "milano - 2014" "varese - 2014" "como - 2014" Ê  Questa  divisione  non  è  fra  due  numeri…  ma  fra  decine  (o  milioni)  di   numeri   Ê  Prendiamo  il  numero  di  docenti  di  ciascuna  università  e  lo   trasformiamo  in  un  fattore  a  4  livelli,  in  modo  da  ottenere  quattro   gruppi  di  università  divisi  per  classe  dimensionale     Ê  Altro  esempio  di  come  R  ragioni  sempre  magicamente  per  vettori  
  • 18. Cose  ancora  più  difficili  in  R:  clustering   dataClustering <- subset(dataK, select=c('i_2’,'i_40’,'i_207’,'i_inf')) rownames(dataClustering) <- dataK$codice_fiscale dataClustering[is.na(dataClustering)==T]<-0 k_cluster <- kmeans(dataClustering, 3) d1 <- data.frame(cluster = k_cluster$cluster, codice_fiscale=names(k_cluster$cluster)) data <- merge(data, d1, by='codice_fiscale') data$cluster<-factor(data$cluster) plot(dataClustering, col=data$cluster)
  • 19. Concludendo   Rispetto  a  fare  l’analisi  in  excel,  il  vantaggio  è  che  si  può…   Ê  …  ripetere  le  analisi  decine  di  volte  con  poco  sforzo,   cambiando  qualche  ipotesi  o  qualche  tipo  di  analisi   Ê  …  aggiungere  dati  (es.  un  anno  di  analisi  in  più)  senza   nessuno  sforzo   Ê  …  analizzare  centinaia  di  migliaia  o  milioni  di  righe   Ê  …  interagire  con  SQL  senza  lavoro  manuale  (una   elaborazione  di  analisi  può  richiedere  decine  di  query)   Ê  …  cambiare  quando  si  vuole  l’ambito  delle  analisi  (es.   vediamo  solo  gli  acquisti  <  1.000  €  nelle  regioni  del  nord)  
  • 20. Grazie       francesco@cavazzana.it