Com vam fer a les PAC1 i PAC2, per a aquesta activitat es pot fer ús d’eines d’IA generativa com a guia per resoldre certs problemes, sempre argumentant-ne l’ús de manera raonada.
En aquesta línia, és fonamental documentar de manera clara i estructurada la interacció amb eines d’intel·ligència artificial generativa (com ChatGPT o d’altres). No es tracta només d’obtenir respostes, sinó d’entendre com aquestes eines poden ajudar-nos a resoldre problemes, prendre decisions i reflexionar críticament sobre els resultats que ofereixen. Per això, proposem una guia que agrupi les preguntes que es plantegen a la IA en cinc categories principals. Aquesta classificació no només facilita l’anàlisi posterior, sinó que també ajuda a identificar patrons en el tipus de suport que cerquem.
Metodologia: Preguntes relacionades amb bones pràctiques, aproximacions recomanades i marcs metodològics.
Programació: Consultes sobre implementació de codi, tant en R com en Python.
Diagnosi: Preguntes orientades a identificar i resoldre errors o comportaments inesperats.
Interpretació: Dubtes sobre com entendre els resultats obtinguts, el seu significat i possibles implicacions.
Extensió: Preguntes obertes que busquen que la IA proposi noves línies de treball, idees o millores.
Per a cada categoria, es documentarà la interacció amb la IA seguint aquest esquema:
Pregunta traslladada a la IA generativa Què s’ha preguntat exactament?
Resposta obtinguda Quin tipus de resposta s’ha rebut? (pot incloure scripts, enllaços, gràfics, explicacions, etc.)
Decisió Què s’ha fet amb aquesta resposta? S’ha aplicat directament, s’ha modificat, s’ha descartat?
Reflexió crítica Quins problemes s’han detectat? Quines millores s’han realitzat? Quins aprenentatges se n’han extret?
Aquesta estructura no només ens permet aprofitar el potencial de la IA generativa com a eina de suport tècnic i metodològic, sinó que també ens obliga a mantenir una actitud crítica i reflexiva sobre el seu ús. Documentar cada interacció amb aquest nivell de detall ens ajuda a entendre millor com prenem decisions, quin tipus d’ajuda cerquem i com podem millorar els nostres processos. A més, ens permet justificar de manera transparent l’ús d’aquestes eines en el context de l’activitat, alineant-se amb bones pràctiques de treball col·laboratiu i responsable.
Tot estudi analític ha de néixer d’una necessitat per part del negoci o d’una voluntat de dotar-lo d’un coneixement i contingut en les dades que només podrem obtenir a través d’una col·lecció de bones pràctiques basades en la Mineria de Dades.
El món de l’analítica de dades es sustenta en 3 eixos:
A. Un d’ells és el profund coneixement que hauríem de tenir del negoci a què tractem de donar respostes mitjançant els estudis analítics.
B. L’altre gran eix és sens dubte les capacitats analítiques que siguem capaços de desplegar i en aquest sentit, les dues pràctiques d’aquesta assignatura pretenen que l’estudiant realitzi un recorregut sòlid per aquest segon eix.
C. El tercer eix són els dades. Les necessitats del negoci s’han de concretar amb preguntes analítiques que al seu torn siguin viables respondre a partir de les dades de què disposem. La tasca d’analitzar les dades és sens dubte important, però la tasca d’identificar-los i obtenir-los ha de ser per a un analista un repte permanent.
Com primera part de l’estudi analític que ens disposem a realitzar, es demana a l’estudiant que completi els següents passos:
Plantejar un problema de analítica de dades detallant-ne els objectius analítics i explica una metodologia per a resoldre’ls d’acord amb lo practicat en les PAC anteriors i també d’acord a lo que s’ha aprés en el material didàctic. (12.5%)
Seleccionar un joc de dades i justificar-ne l’elecció. El joc de dades haurà de tenir capacitats perquè se li puguin aplicar algorismes supervisats i algorismes no supervisats a la PRA2 i haurà d’estar alineat amb el problema analític plantejat al pas anterior. (12.5%)
Realitzar una anàlisi exploratòria de el joc de dades seleccionat. (20%)
Realitzar tasques de neteja i condicionat per poder ser usat en processos de modelatge. (20%)
Aplicar un estudi PCA sobre el joc de dades. Tot i no estar explicat en el material didàctic, es valorarà si en lloc de PCA investigueu pel vostre compte i apliqueu SVD (Single Value Decomposition). (25%)
Recordeu també que és important que (10%):
Requisits mínims del conjunt de dades:
Adjuntem aquí una llista de portals de dades obertes per seleccionar el joc de dades. Es poden utilitzar altres fonts per obtenir el vostre joc de dades, però recordeu de citar-les:
Per a totes les PRA cal documentar a cada apartat de l’exercici pràctic que s’ha fet, perquè s’ha fet i com s’ha fet. Així mateix, totes les decisions i conclusions hauran de ser presentades de forma raonada i clara, contextualitzant els resultats, és a dir, especificant tots i cadascun dels passos que s’hagin dut a terme per resoldre’ls. Finalment, incloeu una conclusió final resumint els resultats obtinguts en la pràctica i indiqueu eventuals citacions bibliogràfiques, fonts internes/externes i materials de recerca.
Moltes entitat financeres atenen diàriament a multitud de clients de gran diversitat de perfils per a donar els seus serveis financers. Un d’aquests serveis són els préstecs bancaris. Quan un client necessita diners però en aquell moment no en disposa de la cuantitat que li cal, pot anar al banc i sol·licitar un préstec per tal que el banc li presti una quantitat de diners que posteriorment seràn retornats amb un interessos. Ara bé, als bancs no els interessa prendre riscos deixant diners a persones o entitats que podrien no respectar les condicions temporals i financeres imposades al contracte del préstec. Per això, els bancs poden negar-se a donar crèdit depenent del seu criteri. Els criteris utilitzats per decidir la elegibilitat d’un préstec són definits pel coneixement del propi banc del sector del negoci, així com també es tenen en compte les dades dels solicitants. En la mateixa línia, els clients que presentin un grau alt de solvència a ulls de l’entitat bancària i a priori, són més susceptibles de rebre crèdit que aquells que no disposen de suficients ingressos o que mostren trets característics relacionats amb una no solvència davant d’un deute. Així doncs, la quantitat de sol·licituds de préstecs que s’han de gestionar pot ser significativament elevada i el treball de prendre les decisions que marcaràn si un crèdit és concedit o no consumeix temps i esforços.
Aquí és on la mineria de dades és excepcionalment útil per a identificar els segments dels clients adients per a donar una préstec. Es tracta doncs d’un problema de classificació on hi ha dos possibles classes. Per tal de mesurar el compliment de l’objectiu definit anteriorment, utilitzaré la proporció de resultats classificats correctament. En aquest cas, el projecte és la creació d’un model predictiu que doni com a resultat a les dades d’un client si és recomanable donar crèdit o si per contra representa un risc elevat. Els objectius són proporcionar una eina que minimitzi el risc de les operacion de gestió de préstecs, que augmenti l’eficiència d’aquests processos i automatitzar-los, millorant la presa de decisions en l’aprovació de crèdits. L’estratègia a seguir comença per escollir un conjunt de dades adequat per a entrenar el model més endavant. Aquest conjunt de dades contindrà les observacions dels diversos clients. Per veure amb quines dades treballem es farà un treball d’anàlisi exploratòria. En aquest punt es busca veure les distribucions de les variables, trobar valors nuls, outliers, formats inconsistents, valorar la normalització d’algunes variables, etc. El següent pas serà fer la neteja i la preparació de les dades. És a dir, tractar tots els aspectes detectats a la fase prèvia per tal de preparar el joc de dades per a que sigui òptim per als processos de modelatje posteriors. Això inclou fer la selecció de característiques. Pel que fa a l’abast del projecte relatiu a la pràctica 1, arriba fins a aquest punt del procés de mineria de dades.
Per a la realització d’aquest projecte, he triat un joc de dades que he trobat a Kaggle , anomenat Loan Predication el qual representa perfectament la problemàtica descrita. Després d’una recerca als diversos recursos proporcionats a l’enunciat, he escollit aquest joc de dades perquè està inspirat en dades reals, conté més de 500 observacions, 5 variables numèriques, 5 variables categòriques i una variable binària(la variable objectiu). Tot i que el dataset va ser penjat fa 8 anys, la tipologia del problema segueix essent relevant actualment. Addicionalment, com que es tracta d’un problema de classificació, el joc de dades admet l’aplicació tant d’un model no supervisat com d’un model supervisat, ignorant la variable objectiu en el primer cas. Per aquestes raons, considero que és un dataset interessant per a la pràctica, ja que és un joc de dades al qual li cal una neteja de dades i em permetrà treballar les meves habilitats analítiques al llarg del projecte de mineria de dades.
El primer de tot és la càrrega del fitxer csv del joc de dades i de les llibreries que s’utilitzaran:
# Instal·lar paquets
if (!require('ggplot2')) install.packages("ggplot2")
## Cargando paquete requerido: ggplot2
## Warning: package 'ggplot2' was built under R version 4.5.2
if (!require('DescTools'))install.packages("DescTools")
## Cargando paquete requerido: DescTools
## Warning: package 'DescTools' was built under R version 4.5.2
if (!require('GGally'))install.packages("GGally")
## Cargando paquete requerido: GGally
## Warning: package 'GGally' was built under R version 4.5.2
if (!require('patchwork'))install.packages("patchwork")
## Cargando paquete requerido: patchwork
## Warning: package 'patchwork' was built under R version 4.5.2
# Incloure llibreries
library(readr)
library(dplyr)
##
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(ggplot2)
library(tidyr)
library(DescTools)
library(corrplot)
## corrplot 0.95 loaded
library(GGally)
library(patchwork)
data <- read_csv("LoanPredictionData.csv")
## Rows: 614 Columns: 13
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (8): Loan_ID, Gender, Married, Dependents, Education, Self_Employed, Pro...
## dbl (5): ApplicantIncome, CoapplicantIncome, LoanAmount, Loan_Amount_Term, C...
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Com es pot veure, en un inici hi ha de 13 columnes, de les quals 8 són de tipus char i 5 són de tipus numèric.
A continuació procedeixo a la verificació del conjunts de dades, busco trobar errors o inconsistències en les dades que m’interessa solucionar per adequar el joc de dades. A partir d’aquí valoraré les mesures possibles i consideraré les alternatives més adients segons el meu criteri.
Faré una primera lectura del joc de dades per començar el diagnòstic de la qualitatde les dades. Es mostren els noms de les columnes i les primeres files:
summary(data)
## Loan_ID Gender Married Dependents
## Length:614 Length:614 Length:614 Length:614
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
##
## Education Self_Employed ApplicantIncome CoapplicantIncome
## Length:614 Length:614 Min. : 150 Min. : 0
## Class :character Class :character 1st Qu.: 2878 1st Qu.: 0
## Mode :character Mode :character Median : 3812 Median : 1188
## Mean : 5403 Mean : 1621
## 3rd Qu.: 5795 3rd Qu.: 2297
## Max. :81000 Max. :41667
##
## LoanAmount Loan_Amount_Term Credit_History Property_Area
## Min. : 9.0 Min. : 12 Min. :0.0000 Length:614
## 1st Qu.:100.0 1st Qu.:360 1st Qu.:1.0000 Class :character
## Median :128.0 Median :360 Median :1.0000 Mode :character
## Mean :146.4 Mean :342 Mean :0.8422
## 3rd Qu.:168.0 3rd Qu.:360 3rd Qu.:1.0000
## Max. :700.0 Max. :480 Max. :1.0000
## NA's :22 NA's :14 NA's :50
## Loan_Status
## Length:614
## Class :character
## Mode :character
##
##
##
##
Per cada sol·licitud de préstec, hi ha informació sobre el gènere, l’estat civil, el número de persones a càrrec, l’educació rebuda, el sou mensual de l’aplicant i del coaplicant en dòlars, la cantitat sol·licitada el milers de dòlars, el període del contracte en mesos, una variable que mostra si l’anterior crèdit va ser retornat, la zona de propietat i finalment la variable objectiu Loan_status(concedit/no concedit). Tot i aquest primer cop d’ull, no es pot saber tots els valor possibles de les variables que a priori semblen categòriques.
Abans de crear les característiques categòriques identificades, cal ocupar-se dels valors buits per tal que no interfereixin en la seva creació.
# Percentatge de valors nuls per característica
round(colSums(is.na(data)) / nrow(data) * 100, 2)
## Loan_ID Gender Married Dependents
## 0.00 2.12 0.49 2.44
## Education Self_Employed ApplicantIncome CoapplicantIncome
## 0.00 5.21 0.00 0.00
## LoanAmount Loan_Amount_Term Credit_History Property_Area
## 3.58 2.28 8.14 0.00
## Loan_Status
## 0.00
Es pot observar que la variable que conté més valors nuls és Credit_history, el qual pot ser degut a que el sol·licitant del préstec encara no n’havia demanat cap. La segueix Self_employed, amb un 5.21% de nuls i LoanAmount amb un 3.58%. Gender i Loan_Amount_Term presenten només al voltant de 2% de valors nuls.
Com es pot observar, la característica Credit_history té el major percentatge de nuls(8.14%). Aquesta representa si l’aplicant té un historial net en el pagament dels préstecs. Probablement siguin valors buits perquè és el primer préstec que realitza un client i no es té un registre històric d’aquest. Aquest fet pot aportar informació valiosa ja que Credit_Histori hauria de tenir molta rellevància al considerar l’aprovació del crèdit. Per no perdre aquesta possible identificació de patrons substituiré els valors nuls per “Missing” i tenir-los en consideració, en comptes d’eliminar-los. En la resta de casos, eliminar les files que continguin valors nuls serà la opció aplicada. La raó és que el percentatge de nuls és relativament baix, menor al 5,5% i la eliminació no implica una pèrdua d’informació considerable.
Aquestes decisions s’han près per simplificar el tractament de nuls i per mantenir la integritat de les mateixes. Em respaldo en que la mida del joc de dades és relativament petita i en que la substitució de valors nuls per mesures de centre podria afectar a la representativitat global de les dades.
Cal afegir que la variable Loan_ID no aporta cap informació per al modelatje així que aquesta característica no és necessària i serà eliminada.
# Eliminació de la columna Loan_ID
data_clean <- data %>%
select(-Loan_ID)
# Eliminació de les files amb nuls excepte per la variable Credit_History
data_clean <- data_clean %>%
filter(if_all(-Credit_History, ~ !is.na(.)))
# Comptar nuls per columna
na_count <- colSums(is.na(data_clean))
# Mostrar només les columnes amb nuls
na_count[na_count > 0]
## Credit_History
## 43
Com es pot veure, ara la única columna que conserva els valors nuls és Credit_History. En el cas de Credit_History, es transformarà a variable ordinal numèrica per poder incloure-la al PCA.
# Modificar valors de Credit_History de pitjor a millor
data_clean$Credit_History <- dplyr::case_when(
data_clean$Credit_History == 0 ~ 0, # historial negatiu
is.na(data_clean$Credit_History) ~ 1, # sense historial
data_clean$Credit_History == 1 ~ 2 # historial positiu
)
# Convertir a numèric
data_clean$Credit_History <- as.numeric(data_clean$Credit_History)
unique(data_clean$Credit_History)
## [1] 2 0 1
D’aquesta manera PCA interpretarà que un aplicant sense historial té menys pes que un amb historial negatiu, que té menys pes que un amb historial positiu per a l’acceptació del préstec.
Ara ja puc procedir a gestionar el format de les característiques candidates a ser factors.
El següent pas és definir com a factors totes les variables aspirants a categòriques, d’aquesta manera podrem visualitzar i interpretar la seva distribució.
# Crear dataset per a les variables categòriques
data_factors <- data_clean
# Seleccionar les variables que seran categòriques
cat_cols <- c("Gender", "Married", "Dependents", "Education", "Self_Employed", "Loan_Amount_Term", "Credit_History", "Property_Area", "Loan_Status")
# Definir com a factors les variables categòriques
data_factors[cat_cols] <- lapply(data_factors[cat_cols], as.factor)
# Comprovar els tipus de cada columna
str(data_factors[cat_cols])
## tibble [523 × 9] (S3: tbl_df/tbl/data.frame)
## $ Gender : Factor w/ 2 levels "Female","Male": 2 2 2 2 2 2 2 2 2 2 ...
## $ Married : Factor w/ 2 levels "No","Yes": 2 2 2 1 2 2 2 2 2 2 ...
## $ Dependents : Factor w/ 4 levels "0","1","2","3+": 2 1 1 1 3 1 4 3 2 3 ...
## $ Education : Factor w/ 2 levels "Graduate","Not Graduate": 1 1 2 1 1 2 1 1 1 1 ...
## $ Self_Employed : Factor w/ 2 levels "No","Yes": 1 2 1 1 2 1 1 1 1 1 ...
## $ Loan_Amount_Term: Factor w/ 10 levels "12","36","60",..: 9 9 9 9 9 9 9 9 9 9 ...
## $ Credit_History : Factor w/ 3 levels "0","1","2": 3 3 3 3 3 3 1 3 3 3 ...
## $ Property_Area : Factor w/ 3 levels "Rural","Semiurban",..: 1 3 3 3 3 3 2 3 2 3 ...
## $ Loan_Status : Factor w/ 2 levels "N","Y": 1 2 2 2 2 2 1 2 1 2 ...
A continuació vull visualitzar les distribucions de les característiques categòriques per veure si hi ha desequilibris. Començo per les variables categòriques perquè em donaran una visió ràpida de la simetria del joc de dades. Després m’enfocaré en analitzar la distribució de les variables numèriques per a la detecció de valors extrems.
Per a les variables categòriques m’interessa la freqüència de Loan_Status, ja que és la variable objectiu, i com es relaciona amb la resta de variables.
# Convertir les variables categòriques a format llarg
data_long <- data_factors %>%
pivot_longer(cols = setdiff(cat_cols, "Loan_Status"), names_to = "Variable", values_to = "Categoria")
names(data_long)
## [1] "ApplicantIncome" "CoapplicantIncome" "LoanAmount"
## [4] "Loan_Status" "Variable" "Categoria"
# Gràfic amb facetes
ggplot(data_long, aes(x = Categoria, fill = Loan_Status)) +
geom_bar(position = "dodge") +
facet_wrap(~ Variable, scales = "free_x") +
labs(title = "Distribució de variables categòriques segons Loan_Status") +
theme_minimal()
A primera vista ja es veu que hi ha fores desequilibris. Hi ha molts més homes que dones que han aplicat per un préstec. S’observa que el més habitual és que les persones que demanen préstecs no tinguin ningú a càrrec. Hi ha molts més graduats que no graduats, quatre cop més de fet. La gran majoria d’aplicants no són autoempleats. També es veu com hi ha més casos de persones que tenen un historial acceptable que no. Potser es deu a que els que no no tornen a demanar crèdit i els que si, si. Tal com era d’esperar, hi ha més préstecs rebutjats que acceptats en el grup d’aplicants amb un mal històric, tot i que alguns han sigut concedits.
Finalment, la distribució de la tipologia de l’àrea de propietat dels aplicants està bastant equilibrada, tot i que la predominant és Semiurban, per la qual el nombre de rejeccions és el més baix i el nombre d’acceptacions és el més alt. Addicionalment es pot observar que Loan_Amount_Term té molt baixa variabilitat i per tant no aporta informació al model, fet que fa pensar que és adequat prescindir-ne.
En resum, sembla que un aplicant home no autoempleat, casat, amb estudis completats, sense persones al càrrec, que viu en una zona semirural i té un bon històric al banc és un bon candidat per a que li concedeixin un préstec. Això porta a pensar que la majoria d’aplicants són gent que ja ha demanat algun préstec prèviament. Sembla que el segment dels clients susceptibles de conseguir crèdit és força específic però no pas reduït.
A continuació visualitzaré les dependències entre cada parell de variables amb una matriu de Cramer, que mesura la força de l’associació entre variables.
# Seleccionar només variables categòriques
cat_cols <- c("Gender", "Married", "Dependents", "Education",
"Self_Employed", "Loan_Amount_Term", "Credit_History", "Property_Area", "Loan_Status")
# Calcular matriu de Cramer’s V
cramer_matrix <- sapply(cat_cols, function(x) {
sapply(cat_cols, function(y) {
CramerV(table(data_factors[[x]], data_factors[[y]]))
})
})
# Convertir a matriu
cramer_matrix <- matrix(unlist(cramer_matrix),
nrow = length(cat_cols),
byrow = TRUE,
dimnames = list(cat_cols, cat_cols))
# Visualitzar
corrplot(cramer_matrix, method = "color", type = "upper", tl.cex = 0.8)
Am la matriu de Cramer es mostren les associacions entre les variables categòriques. En aquest cas és notable que Loan_Status depèn de Credit_History, ja que tenen un 0.6 de puntuació. Altres associacions són Gender i Married(0.4) i Married i Dependents(0.4). Això mostra el que s’ha vist abans que la majoria dels aplicants eren casats i sense dependents. Per a la resta de variables no s’observa cap dependència significativa. El que si que es pot notar és que Loan_Status no té cap dependència sobre les variables Gender i Self_Employed. Es pot veure que per a Loan_Amount_Term sembla que existeix algu grau d’associació amb la resta de variables. Pot ser causat perquè gairebés tots els valors són de 360 mesos, és a dir no té variabilitat. Conservaré aquesta característica perquè tot i tenir variància baixa, pot estar correlacionada amb alguna altra.
Seguiré endavant amb l’estudi de la distribució de les variables numèriques. Primer es mostren histogrames per veure la distribució individual de les variables.
# Dades numèriques
data_num <- data_factors
# Seleccionar variables numèriques
numeric_cols <- c("ApplicantIncome", "CoapplicantIncome", "LoanAmount")
# Crear llista de gràfics
plots <- lapply(numeric_cols, function(var) {
ggplot(data_num, aes_string(x = var)) +
geom_histogram(bins = 50, fill = "steelblue", color = "white") +
labs(title = paste("Histograma de", var), x = var, y = "Freqüència") +
theme_minimal()
})
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## ℹ Please use tidy evaluation idioms with `aes()`.
## ℹ See also `vignette("ggplot2-in-packages")` for more information.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
# Combinar en matriu (2 columnes)
final_plot <- wrap_plots(plots, ncol = 2) +
plot_annotation(title = "Distribució de variables numèriques")
final_plot
Els anteriors histogrames mostren que totes les característiques graficades presenten outliers. ApplicantIncome presenta un valor extrem 80000 i d’altres al voltant de 40000. CoapplicantIncome té un outlier per sobre de 30000, un a 20000 i un altre sobre 10000. En quant al tamany dels préstecs, el més habitual és que estiguin al voltant de 120000 i que no sobrepassin els 300000. Les tres variables presenten distribucions amb biaix a l’esquerra.
A continuació es visualitza la distribució de les variables numèriques, juntament amb la seva correlació segons Loan_Status.
ggpairs(
data_num,
columns = c(6:8), # només numèriques
mapping = aes(color = Loan_Status), # color segons Loan_Status
diag = list(continuous = "barDiag"), # histogrames a la diagonal
)
## `stat_bin()` using `bins = 30`. Pick better value `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value `binwidth`.
Aquesta matriu de gràfics informa de les correlacions entre les variables mostrades segons l’acceptació ono dels préstecs. Es pot veure que la que mostra més correlació és el parell ApplicantIncome i LoanAmount. Per tant tenim que aquestes variables estàn correlacionades i que els ingressos de l’aplicant afecten directament a la cantitat de diners del préstec. Es pot veure també que les distribucions presenten biax a l’esquerra, per exemple per aquells pocs aplicants que tenen uns ingressos extremadament alts. Per tal de lidiar amb aquests outliers primer aplicaré una transformació logarítmica per controlar-los.
# Crear dataset amb les transformacions log
data_transform <- data_num %>%
mutate(
ApplicantIncome_log = log(ApplicantIncome + 1),
CoapplicantIncome_log = log(CoapplicantIncome + 1),
LoanAmount_log = log(LoanAmount + 1)
)
# Crear llista de gràfics
plots <- list(
ggplot(data_transform, aes(x = ApplicantIncome)) +
geom_histogram(bins = 50, fill = "lightblue", color = "white") +
labs(title = "ApplicantIncome original") +
theme_minimal(),
ggplot(data_transform, aes(x = ApplicantIncome_log)) +
geom_histogram(bins = 50, fill = "lightgreen", color = "white") +
labs(title = "ApplicantIncome log") +
theme_minimal(),
ggplot(data_transform, aes(x = CoapplicantIncome)) +
geom_histogram(bins = 50, fill = "lightblue", color = "white") +
labs(title = "CoapplicantIncome original") +
theme_minimal(),
ggplot(data_transform, aes(x = CoapplicantIncome_log)) +
geom_histogram(bins = 50, fill = "lightgreen", color = "white") +
labs(title = "CoapplicantIncome log") +
theme_minimal(),
ggplot(data_transform, aes(x = LoanAmount)) +
geom_histogram(bins = 50, fill = "lightblue", color = "white") +
labs(title = "LoanAmount original") +
theme_minimal(),
ggplot(data_transform, aes(x = LoanAmount_log)) +
geom_histogram(bins = 50, fill = "lightgreen", color = "white") +
labs(title = "LoanAmount log") +
theme_minimal()
)
# Combinar en matriu (2 columnes, 3 files)
final_plot <- wrap_plots(plots, ncol = 2) +
plot_annotation(title = "Comparació de distribucions originals vs log-transformades")
final_plot
Ara les dades mostren una distribució més simètrica i ja no presenten les cues anteriors. Això implica que les distribucions s’aproximen més a una normal i els valors extrems perden protagonisme, el qual equilibra la variabilitat i optimitza la detecció d’outliers. Ara que ja estan més controlats els valors extrems procediré a la seva detecció i eliminació. Aquest pas el realitzo posteriorment a la tranformació logarítmica perquè altrament es podrien detectar més outliers deguda la distribució descontrolada i causaria pèrdua de variabilitat a les dades.
# Seleccionar variables
log_cols <- c(13:15)
log_data <- data_transform[log_cols]
# Calcular Z-scores
z_scores <- scale(log_data)
z_scores_df <- as.data.frame(z_scores)
# Files amb algun outlier
rows_outliers <- apply(z_scores_df, 1, function(row) any(abs(row) > 3))
# Comptar quants outliers hi ha
sum(rows_outliers)
## [1] 14
Amb el paràmetre z > 3 s’han detectat 14 outliers, els quals seràn eliminats per reduïr el soroll.
# Eliminar outliers
data_no_outliers <- data_transform[!rows_outliers, ]
# Mostrar abans i després
par(mfrow=c(1,2))
# ApplicantIncome
boxplot(data_transform$ApplicantIncome, main="Abans")
boxplot(data_no_outliers$ApplicantIncome, main="Després")
# CoapplicantIncome
boxplot(data_transform$CoapplicantIncome, main="Abans")
boxplot(data_no_outliers$CoapplicantIncome, main="Després")
# LoanAmount
boxplot(data_transform$LoanAmount, main="Abans")
boxplot(data_no_outliers$LoanAmount, main="Després")
Com es pot veure s’ha reduït la variància de les variables dins d’un límit que ens permeti conservar la informació al joc de dades. Per a CoapplicantIncome no ha canviat gaire deguda la distància interior de les dades. Es pot extreure d’aquests gràfics que la majoria d’outliers han sigut de la variable ApplicantIncome.
Una vegada les dades estan netes de valors extrems, el següent pas és normalitzar-les. Faré servir la normalització típica. Un altre aspecte a tenir en compte és la diferència de l’escala dels valors entre les variables numèriques. Els valors de la columna LoanAmount estan representats en milers, mentre que les altres columnes referents a quantitat de diners s’expressen en unitats. La normalització evitarà que en el procés de PCA, es prenguin certes característiques com a més rellevants degut a la major magnitud dels seus valors. Es normalitzaran tots els valors de les característiques numèriques perquè tinguin mitjana 0 i desviació estàndard 1, el qual fa que totes les variables contribueixin de manera comparable al càlcul de components principals en PCA.
# Variables normalitzades
data_norm <- scale(data_no_outliers[,log_cols])
# Variables categòriques
data_cat <- data_no_outliers[,setdiff(cat_cols, "Loan_Status")]
# Variable objectiu
target <- data_no_outliers$Loan_Status
# Dataset definitiu
final_data <- cbind(data_cat, data_norm, Loan_Status = target)
# Ajustar noms
final_data <- final_data %>%
rename(
ApplicantIncome_log_norm = ApplicantIncome_log,
CoapplicantIncome_log_norm = CoapplicantIncome_log,
LoanAmount_log_norm = LoanAmount_log
)
head(final_data)
## Gender Married Dependents Education Self_Employed Loan_Amount_Term
## 1 Male Yes 1 Graduate No 360
## 2 Male Yes 0 Graduate Yes 360
## 3 Male Yes 0 Not Graduate No 360
## 4 Male No 0 Graduate No 360
## 5 Male Yes 2 Graduate Yes 360
## 6 Male Yes 0 Not Graduate No 360
## Credit_History Property_Area ApplicantIncome_log_norm
## 1 2 Rural 0.1800446
## 2 2 Urban -0.5980748
## 3 2 Urban -0.8728737
## 4 2 Urban 0.6747958
## 5 2 Urban 0.4870755
## 6 2 Urban -1.0597780
## CoapplicantIncome_log_norm LoanAmount_log_norm Loan_Status
## 1 0.7689174 -0.01308317 N
## 2 -1.1207969 -1.44791573 Y
## 3 0.8842724 -0.15330279 Y
## 4 -1.1207969 0.19720654 Y
## 5 1.0330216 1.58832334 Y
## 6 0.7702826 -0.66020402 Y
Amb l’objectiu de preparar les dades per a poder fer PCA, la variable objectiu serà exclosa, ja que PCA podria distorsionar els resultats si és inclosa en les dades d’entrada. Les variables categòriques seran transformades fent el one-hot-encoding, ja que per construir la matriu de correlacions són necessàries dades numèriques. En el cas de Loan_Amount_Term s’utilitzaran els valors numèrics que hem modificat com factors per la visualització. I pel que fa a Credit_History, també assignaré valors numèrics ja que els nivells definits corresponen a un ordre de prioritat per concedir un crèdit.
library(fastDummies)
## Warning: package 'fastDummies' was built under R version 4.5.2
# Joc de dades per fer PCA sense LoanStatus (variable objectiu)
pca_data <- final_data %>% select(-Loan_Status)
# Comprobar que els nivells estiguin correctament ordenats
levels(final_data$Loan_Amount_Term)
## [1] "12" "36" "60" "84" "120" "180" "240" "300" "360" "480"
levels(final_data$Credit_History)
## [1] "0" "1" "2"
# Transformar Loan_Amount_Term i Credit_History a numeric
pca_data$Loan_Amount_Term <- as.numeric(pca_data$Loan_Amount_Term)
pca_data$Credit_History <- as.numeric(pca_data$Credit_History)
# Fer el one-hot encoding de les variables categòriques
pca_data <- dummy_cols(
pca_data,
select_columns = c("Gender", "Married", "Dependents", "Education", "Self_Employed", "Property_Area"),
remove_selected_columns = TRUE
)
# Comprobar que totes les variables són numèriques
str(pca_data)
## 'data.frame': 509 obs. of 20 variables:
## $ Loan_Amount_Term : num 9 9 9 9 9 9 9 9 9 9 ...
## $ Credit_History : num 3 3 3 3 3 3 1 3 3 3 ...
## $ ApplicantIncome_log_norm : num 0.18 -0.598 -0.873 0.675 0.487 ...
## $ CoapplicantIncome_log_norm: num 0.769 -1.121 0.884 -1.121 1.033 ...
## $ LoanAmount_log_norm : num -0.0131 -1.4479 -0.1533 0.1972 1.5883 ...
## $ Gender_Female : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Gender_Male : int 1 1 1 1 1 1 1 1 1 1 ...
## $ Married_No : int 0 0 0 1 0 0 0 0 0 0 ...
## $ Married_Yes : int 1 1 1 0 1 1 1 1 1 1 ...
## $ Dependents_0 : int 0 1 1 1 0 1 0 0 0 0 ...
## $ Dependents_1 : int 1 0 0 0 0 0 0 0 1 0 ...
## $ Dependents_2 : int 0 0 0 0 1 0 0 1 0 1 ...
## $ Dependents_3+ : int 0 0 0 0 0 0 1 0 0 0 ...
## $ Education_Graduate : int 1 1 0 1 1 0 1 1 1 1 ...
## $ Education_Not Graduate : int 0 0 1 0 0 1 0 0 0 0 ...
## $ Self_Employed_No : int 1 0 1 1 0 1 1 1 1 1 ...
## $ Self_Employed_Yes : int 0 1 0 0 1 0 0 0 0 0 ...
## $ Property_Area_Rural : int 1 0 0 0 0 0 0 0 0 0 ...
## $ Property_Area_Semiurban : int 0 0 0 0 0 0 1 0 1 0 ...
## $ Property_Area_Urban : int 0 1 1 1 1 1 0 1 0 1 ...
Ara ja es disposa de les dades preparades per a fer el PCA. El primer pas del procés d’extracció de components principals és construir la matriu de correlacions, que permet veure com es relacionen les variables entre elles. El següent pas consisteix a calcular els valors propis i els vectors propis de cada component i finalment decidir quins components seran retinguts per visualitzar i interpretar els resultats.
# PCA
pca_result <- prcomp(pca_data, center = TRUE, scale. = TRUE)
# Resum
summary(pca_result)
## Importance of components:
## PC1 PC2 PC3 PC4 PC5 PC6 PC7
## Standard deviation 1.8356 1.5319 1.4477 1.30116 1.27891 1.17066 1.12385
## Proportion of Variance 0.1685 0.1173 0.1048 0.08465 0.08178 0.06852 0.06315
## Cumulative Proportion 0.1685 0.2858 0.3906 0.47524 0.55702 0.62555 0.68870
## PC8 PC9 PC10 PC11 PC12 PC13 PC14
## Standard deviation 1.09971 1.0412 1.01119 0.97954 0.96450 0.87304 0.50814
## Proportion of Variance 0.06047 0.0542 0.05113 0.04797 0.04651 0.03811 0.01291
## Cumulative Proportion 0.74917 0.8034 0.85449 0.90247 0.94898 0.98709 1.00000
## PC15 PC16 PC17 PC18 PC19
## Standard deviation 9.969e-16 8.93e-16 5.424e-16 3.63e-16 2.834e-16
## Proportion of Variance 0.000e+00 0.00e+00 0.000e+00 0.00e+00 0.000e+00
## Cumulative Proportion 1.000e+00 1.00e+00 1.000e+00 1.00e+00 1.000e+00
## PC20
## Standard deviation 6.623e-17
## Proportion of Variance 0.000e+00
## Cumulative Proportion 1.000e+00
# Variància explicada per cada component
explained_var <- pca_result$sdev^2 / sum(pca_result$sdev^2)
# Percentatge acumulat
cum_var <- cumsum(explained_var)
# Taula resum
pca_summary <- data.frame(
Component = paste0("PC", 1:length(explained_var)),
Variance_Explained = round(explained_var * 100, 2),
Cumulative_Variance = round(cum_var * 100, 2)
)
print(pca_summary)
## Component Variance_Explained Cumulative_Variance
## 1 PC1 16.85 16.85
## 2 PC2 11.73 28.58
## 3 PC3 10.48 39.06
## 4 PC4 8.47 47.52
## 5 PC5 8.18 55.70
## 6 PC6 6.85 62.55
## 7 PC7 6.32 68.87
## 8 PC8 6.05 74.92
## 9 PC9 5.42 80.34
## 10 PC10 5.11 85.45
## 11 PC11 4.80 90.25
## 12 PC12 4.65 94.90
## 13 PC13 3.81 98.71
## 14 PC14 1.29 100.00
## 15 PC15 0.00 100.00
## 16 PC16 0.00 100.00
## 17 PC17 0.00 100.00
## 18 PC18 0.00 100.00
## 19 PC19 0.00 100.00
## 20 PC20 0.00 100.00
En aquesta taula es mostra la variància explicada per cada component extret. Es veu que només les primeres tres variables expliquen juntes un 40% de les dades. El percentatge restant està repartit en la resta de components(17). També es pot veure que a partir del component 15 ja no expliquen variància.
Es pot determinar el nombre òptim de components que cal conservar segons la definició del percentatge de variància mínim que es vol acumular.
# Scree plot
plot(explained_var, type = "b", xlab = "Component", ylab = "Proporció de variància explicada")
# Recomanació: components fins a 90% de variància acumulada
recommended <- which(cum_var >= 0.9)[1]
cat("Recomanació: mantenir fins al component", recommended,
"per explicar almenys el 90% de la variància.\n")
## Recomanació: mantenir fins al component 11 per explicar almenys el 90% de la variància.
Segons el resultat es té que per explicar el 90% de la variància és recomanable conservar els 11 primers components. Els components són combinacions de les variables originals que contenen la informació de les originals. L’objectiu del PCA és seleccionar només aquelles que expliquen la major part de la variància, reduïnt la quantitat de variables. Una vegada determinat el nombre òptim de components a conservar, l’últim pas és eliminar aquelles compontent que no són rellevants.
k <- recommended
# Projectar les dades sobre els primers k components
pca_data_reduced <- pca_result$x[, 1:k]
# Convertir a data.frame per treballar còmodament
pca_data_reduced <- as.data.frame(pca_data_reduced)
# Comprovació
head(pca_data_reduced)
## PC1 PC2 PC3 PC4 PC5 PC6
## 1 1.6358510 -0.2072402 -0.6567867 0.26657992 0.2793481 1.2947308
## 2 0.1935007 -1.9288895 1.2665377 -0.13084464 1.7474019 -2.7633244
## 3 0.9006890 2.5687499 1.2536698 0.18487169 0.9358386 -0.9573272
## 4 -1.5018231 -0.4007063 -0.8006543 1.08140195 1.8671543 -0.2623387
## 5 2.5384185 -3.2323099 0.9165869 -0.47520064 1.0205611 -1.5612209
## 6 0.7701036 2.7755853 1.3187211 0.08314103 1.0430288 -1.0713408
## PC7 PC8 PC9 PC10 PC11
## 1 -1.4793572651 1.25185203 -0.7325239 1.86173492 0.20581665
## 2 -0.4197324645 -0.58436331 1.6255848 -0.03772778 1.12403498
## 3 -0.0004421298 -0.24454944 -0.6704129 -1.20596690 1.46254423
## 4 1.8389175780 0.03078787 -0.3623280 -0.23035666 0.18956085
## 5 -0.4474426445 -2.03711071 -0.3429879 -0.50293548 0.06584582
## 6 -0.0402341869 -0.31709503 -0.3898791 -0.97978408 1.42304573
Finalment, aquestes són les components amb les que es construirà el model de classificació sobre el valor de la classe Loan_Status.
Documentació de la interacció amb IA generativa
Pregunta traslladada a la IA generativa: S’ha demanat consell a la IA de Copilot sobre els passos a seguir i l’ordre adequat per a fer el preprocessament de les dades, així com per a realitzar el procés de PCA.
Resposta obtinguda: Copilot ha respost amb explicacions alineades amb els objectius plantejats, les quals incloien seqüències de passos a seguir, així com una proposició de continuació o de creació de codi a final.
Decisió Què s’ha fet amb aquesta resposta? S’ha aplicat directament, s’ha modificat, s’ha descartat?: Les respostes han servit de guia de bones pràctiques alhora que m’han aportat plantejaments a preguntes anteriorment no considerades com a continuació del flux de treball. Es podria dir que m’han inspirat en aspectes més tècnics i m’han ajudat a seguir els passos en l’ordre correcte. No obstant, no he seguit totes les indicacions que Copilot m’ha proposat, en alguna ocasió he redirigit la consulta cap al meu objectiu principal del moment.
Reflexió crítica: La majoria de respostes ha sigut adequades i productives. Amb poca informació de context Copilot és capaç de proposar alternatives a un mateix problema mostrant el procediment a seguir. Les seves aportacions han sigut útils però, com sempre, cal valorar-les abans d’aplicar-les, ja que no sempre són les més adequades a la primera resposta, cal aprofundir més per conèixer el procediment òptim, a vegades fent consultes en diferents moments de la pràctica i amb distància entre elles per a un mateix aspecte.
Pregunta traslladada a la IA generativa: S’han sol·licitat solucions de codi per a funcions específiques o per a implementar procediments obtinguts a les consultes sobre metodologia. Addicionalment s’han refinat algunes propostes per tal de millorar la flexibilitat i la reproductibilitat del codi.
Resposta obtinguda: Copilot ha proporcionat solucions efectives i, si es demana proposa alternatives per a la mateixa funció. Cal comentar que el codi obtingut no sol ser el més adequat i cal demanar un millor si es vol obtenir una manera de visualitzar les dades més elegant i personalitzable o una més simple segons convingui.
Decisió: Les respostes obtingudes s’han evaluat amb la posada en pràctica i demanant millores en els casos necessaris. A vegades he hagut d’especificar requisits per tal que em fossin útils els resultats.
Reflexió crítica: Copilot proporciona una capacitat enorme per obtenir i utilitzar les eines necessàries per fer un anàlisi exploratori de dades. He descobert llibreries molt útils per a les visualitzacions i per al tractament de les dades que faciliten molt la feina. M’ha estalviat temps i la interacció ha sigut fàcil.
Pregunta traslladada a la IA generativa: He consultat amb la IA sobre la idoneïtat de les decisions preses segons el context i els requisits per tal que em proporcioni la informació per poder decidir la millor alternativa en cada cas. També he consultat codi que produia errors per solucionar-los.
Resposta obtinguda: Copilot ha respost correctament a totes les meves peticions, oferint explicacions raonades a les meves propostes i ajudant-me a detectar errors d’execució. En el cas dels errors de codi ha sigut molt senzill i ràpid ja que s’ha proporcionat el codi corregit i la explicació pertinent en format breu.
Decisió: El procés de diagnosi ha requerit que jo em planteji la conveniència d’aplicar una decisió a un resultat proposat per la IA, que pot no ser correcte, però la mateixa IA, amb la pregunta adequada, m’ha ajudat a solucionar-ho.
Reflexió crítica: Per la identificació d’errors o comportaments inesperats cal proporcionar la informació contextual adequada per tal que la IA sigui útil. A vegades no n’hi ha prou amb proporcionar el codi erroni, sino que cal canviar el nivell d’abstracció i preguntar a la IA sobre si el que estas fent realment té sentit per al teu objectiu. Per tant, mantenir l’alineament amb els objectius és bàsic per obtenir ajuda de la IA.
Pregunta traslladada a la IA generativa: S’ha preguntat a Copilot sobre el significat d’alguns resultats de les visualitzacions i també sobre decisions de tractament de variables segons la seva distribució i format i detecció d’outliers.
Resposta obtinguda: La majoria de preguntes han sigut de resposta si o no, per assegurar que el plantejament fos correcte. Les respostes obtingudes sempre han anat acompanyades de la seva justificació, de manera clara i breu.
Decisió: Les respostes a les consultes sobre diagnosi de plantejaments o decisions les he utilitzat per afavorir raonaments i decantar-me cap a una opció determinada en el cas del tractament de variables. La resta han sigut útils per validar o corregir alguna acció feta.
Reflexió crítica: Copilot és efectiu en el paper d’ajudant de diagnòstic, però no és recomanable dependre totalment de la seva resposta, ja que en ocasions cal redirigir la pregunta per tal que s’obtingui una resposta coherent. En general, però, m’ha ajudat molt a obtenir informació de manera ràpida. També és veritat que l’aprofundiment per part meva ha sigut necessari per arribar a conclusions.