Classifica le professioni ESCO L4 piu' affini a un insieme di competenze
Source:R/match_professions.R
match_professions.RdA partire da un vettore di identificativi ESCO L3 dichiarati dall'utente, costruisce il profilo empirico di ogni professione ESCO L4 (a partire dalle offerte di lavoro) e ne calcola la distanza dal profilo desiderato. Le professioni vengono ordinate per distanza crescente e per ogni professione viene restituita la decomposizione del contributo di ciascuna competenza alla distanza totale.
Usage
match_professions(
skills,
postings,
skills_long,
basis = c("coverage", "tfidf", "rca"),
top_n = 20L,
min_postings = 30L,
skill_labels = NULL,
weights = NULL
)Arguments
- skills
Vettore character di identificativi ESCO L3 (
idescoskill_level_3). EventualiNAe duplicati vengono rimossi.- postings
data.tablecon almeno le colonnegeneral_ideidesco_level_4. Tipicamente ottenuto daread_oja_itaposts(con)$postings:itaposts::oja_postings()da sola non esponeidesco_level_4.- skills_long
data.tablein formato lungo con almeno le colonnegeneral_ideidescoskill_level_3. Una riga per coppia (annuncio, competenza). Tipicamente ottenuto daread_oja_itaposts(con)$skills.- basis
Base del profilo professionale:
"coverage"(default),"tfidf"oppure"rca".- top_n
Numero intero di professioni da restituire in
rankinge per le quali emettere la decomposizioneper_skill. Default20L.- min_postings
Numero minimo di annunci per professione necessari per ritenere stabile il profilo. Le professioni sotto soglia vengono scartate prima del calcolo. Default
30L.- skill_labels
data.tableopzionale con almeno le colonneidescoskill_level_3eescoskill_level_3(etichetta leggibile). Quando fornito, la tabellaper_skillottiene la colonnaskill_label. DefaultNULL. Tipicamente ottenuto deduplicando le due colonne suread_oja_itaposts(con)$skills:itaposts::oja_skill_dim()espone l'etichetta comeesco_v010200_label, non comeescoskill_level_3.- weights
Vettore numerico non negativo di pesi per le competenze in
skills. SeNULL(default) tutte le competenze ricevono peso uniforme. Quando fornito deve avere lunghezza pari alength(skills)dopo deduplicazione diNAe duplicati; vedimatch_professions_score()per i dettagli.
Value
Una list con i seguenti elementi:
rankingdata.tablecon una riga per professione (al piu'top_n), ordinata perdistancecrescente. Colonne:idesco_level_4,distance(in[0, 1]),score = 1 - distance,hit_ratio(frazione delle competenze dichiarate che la professione richiede almeno una volta; nel caso pesato e' la massa quadratica delle competenze matchate normalizzata sulla massa totale),mean_coverage(media dicoverage_{p,s}sulle competenze dichiarate;NAsebasis != "coverage"),n_postings,n_skills_matched.per_skilldata.tablein formato lungo con una riga per ciascuna coppia (professione top-N, competenza con contributo non nullo). La lista delle righe include sia le competenze dichiarate sia quelle richieste dalla professione ma non dichiarate, in modo che valga l'identita' additivasum(contribution) == distanceper ogni professione. Colonne:idesco_level_4,idescoskill_level_3,skill_label(NAseskill_labelsnon fornito),declared(logico,TRUEse la competenza e' nella query),profile_value(valore grezzo div_p[s]nella base scelta, pre-normalizzazione;NAse la competenza non e' nell'universo della professione),contribution(addendo della distanza),contribution_pct(contribution / distance;NAsedistance == 0).basisLa base usata, per introspezione.
queryIl vettore
skillsdeduplicato.paramsLista con
top_n,min_postings,n_professions_considered,n_skills_in_universe,n_skills_resolved,n_skills_unresolved.
Nota sull'invariante: la somma di contribution su tutte le righe di
per_skill per una data professione coincide con distance perche'
sono incluse anche le competenze richieste dalla professione ma non
dichiarate. Filtrando su declared == TRUE la somma sara' invece
inferiore a distance, e il divario rappresenta la massa che la
professione richiede al di fuori della query.
Details
Questa funzione e' un wrapper sottile su
match_professions_prepare() + match_professions_score(). Per uso ad
alta frequenza (per esempio dashboard interattive) e' preferibile
invocare match_professions_prepare() una sola volta per data refresh
e chiamare match_professions_score() ad ogni interazione utente: la
costruzione della matrice profilo e' il costo dominante.
La distanza usata e' la distanza coseno (1 - cos(v_p, q)), equivalente
a meta' della distanza euclidea quadrata fra vettori L2-normalizzati.
Questa scelta e' l'unica metrica della famiglia che fornisce una
decomposizione additiva pulita per singola competenza:
$$1 - \cos(v_p, q) = \frac{1}{2} \sum_s ( \tilde v_{p,s} - \tilde q_s )^2.$$
Il profilo v_p di ogni professione e' costruito secondo la base scelta:
coveragen_{p,s} / N_p, probabilita' che un annuncio diprichiedas. Interpretabile come quota di copertura.tfidftf_{p,s} * idf_scontf_{p,s} = n_{p,s} / sum_s n_{p,s}calcolata internamente alla professione, eidf_s = log(P / df_s)dovedf_se' il numero di professioni che richiedonos(dopo filtromin_postings) ePil numero totale di professioni superstiti. Pesa di piu' le competenze discriminanti.rcaindice di Balassa, delegato a
compute_balassa_index(). Misura la specializzazione:>1indica sovra-rappresentazione.
Il vettore di query q e' costruito a partire da weights (default
uniforme 1 su ogni competenza dichiarata); sia q che le colonne di
M vengono L2-normalizzati prima del calcolo.
See also
match_professions_prepare() e match_professions_score()
per il workflow "prepara una volta, scoring molte volte",
compute_profession_distance() per la distanza fra professioni,
compute_balassa_index() per l'indice di Balassa usato dalla base
rca, build_skill_prof_sparse() per la matrice competenze x
professioni.
Examples
if (FALSE) { # \dontrun{
con <- itaposts::oja_connect()
on.exit(itaposts::oja_disconnect(con), add = TRUE)
ojv <- skillviz::read_oja_itaposts(con)
# le etichette leggibili viaggiano con le righe di skill
labs <- unique(ojv$skills[, .(idescoskill_level_3, escoskill_level_3)])
# convenience: end-to-end in una sola chiamata
res <- skillviz::match_professions(
skills = c("S1.4.1", "S4.8.1", "S1.13.2"),
postings = ojv$postings,
skills_long = ojv$skills,
basis = "coverage",
top_n = 10,
skill_labels = labs
)
res$ranking
res$per_skill[idesco_level_4 == res$ranking$idesco_level_4[1L]]
# prepara una volta, scoring molte volte
prep <- skillviz::match_professions_prepare(
ojv$postings, ojv$skills, basis = "coverage"
)
res1 <- skillviz::match_professions_score(prep, c("S1.4.1", "S4.8.1"))
res2 <- skillviz::match_professions_score(
prep, c("S2.1.3"), weights = c(2.0)
)
} # }