anorexia: tipus de dades, NA/NULL i
recodificacióbirthwtPrewt i PostwtTract_PulmoChickWeightanorexia_treat_df# Creem (si no existeixen) les carpetes on desarem les dades i els resultats
dir.create("dades", showWarnings = FALSE)
dir.create("sortides", showWarnings = FALSE)
Enunciat: comproveu quins paquets teniu instal·lats,
instal·leu MASS i survival, comproveu la
informació que contenen i busqueu informació sobre Rcmdr
des de la consola.
A la consola, library() sense arguments obre una
finestra amb tots els paquets instal·lats. Dins d’un document és més
útil fer-ho amb installed.packages(), que retorna una
matriu (una fila per paquet):
paquets <- rownames(installed.packages())
length(paquets) # quants paquets tinc instal·lats
## [1] 178
head(paquets, 15) # els 15 primers
## [1] "abind" "backports" "base" "base64enc" "bit"
## [6] "bit64" "boot" "broom" "bslib" "ca"
## [11] "cachem" "car" "carData" "careless" "cellranger"
# Estan instal·lats MASS i survival?
c("MASS", "survival") %in% paquets
## [1] TRUE TRUE
Per instal·lar-los s’usa install.packages(). Posem
eval=FALSE al chunk perquè no es reinstal·lin cada vegada
que fem Knit:
install.packages("MASS")
install.packages("survival")
install.packages("Rcmdr")
Un cop instal·lats, cal carregar-los amb
library() per usar-los, i podem veure’n la informació
(descripció, funcions i conjunts de dades):
library(MASS)
library(survival)
packageDescription("MASS")$Title
## [1] "Support Functions and Datasets for Venables and Ripley's MASS"
packageDescription("survival")$Title
## [1] "Survival Analysis"
packageVersion("MASS")
## [1] '7.3.66'
library(help = "MASS") # índex complet del paquet
library(help = "survival")
Per buscar informació sobre Rcmdr (R Commander) des de
la consola (són ordres interactives, per això
eval=FALSE):
??Rcmdr # cerca a tota l'ajuda instal·lada
help.search("Rcmdr") # equivalent a ??Rcmdr
Per poder practicar sense dependre de fitxers externs, primer
creem dos fitxers d’exemple a la carpeta
dades/ (un .txt separat per tabuladors i un
.csv).
write.table(airquality, "dades/airquality.txt", sep = "\t", row.names = FALSE)
write.csv(MASS::Pima.tr, "dades/pima.csv", row.names = FALSE)
summary() de tres variablesread.table() llegeix fitxers de text.
header = TRUE indica que la primera fila conté els noms de
les variables i sep = "\t" que el separador és el
tabulador.
dades_txt <- read.table("dades/airquality.txt", header = TRUE, sep = "\t")
head(dades_txt)
# summary() de tres variables: seleccionem les columnes pel nom
summary(dades_txt[, c("Ozone", "Temp", "Wind")])
## Ozone Temp Wind
## Min. : 1.00 Min. :56.00 Min. : 1.700
## 1st Qu.: 18.00 1st Qu.:72.00 1st Qu.: 7.400
## Median : 31.50 Median :79.00 Median : 9.700
## Mean : 42.13 Mean :77.88 Mean : 9.958
## 3rd Qu.: 63.25 3rd Qu.:85.00 3rd Qu.:11.500
## Max. :168.00 Max. :97.00 Max. :20.700
## NA's :37
.csv i fivenum() de dues
variablesAmb read.csv() (R base) o readr::read_csv()
llegim fitxers .csv. fivenum() retorna els
cinc números de Tukey: mínim, Q1, mediana, Q3 i
màxim.
library(readr)
dades_csv <- read_csv("dades/pima.csv", show_col_types = FALSE)
head(dades_csv)
fivenum(dades_csv$glu) # glucosa en plasma
## [1] 56.0 100.0 120.5 144.0 199.0
fivenum(dades_csv$bmi) # índex de massa corporal
## [1] 18.20 27.55 32.80 36.50 47.90
anorexia: tipus de dades, NA/NULL i
recodificaciódata("anorexia") # ja hem carregat MASS a l'exercici 1
head(anorexia)
Tipus de dades que conté: str() mostra
l’estructura i class() el tipus de cada variable.
str(anorexia)
## 'data.frame': 72 obs. of 3 variables:
## $ Treat : Factor w/ 3 levels "CBT","Cont","FT": 2 2 2 2 2 2 2 2 2 2 ...
## $ Prewt : num 80.7 89.4 91.8 74 78.1 88.3 87.3 75.1 80.6 78.4 ...
## $ Postwt: num 80.2 80.1 86.4 86.3 76.1 78.1 75.1 86.7 73.5 84.6 ...
sapply(anorexia, class) # aplica class() a cada columna
## Treat Prewt Postwt
## "factor" "numeric" "numeric"
Treat és un factor (variable categòrica
amb 3 nivells) i Prewt i Postwt són
numèriques (pes abans i després, en lliures).
Valors NA i NULL:
NA = valor perdut dins de les dades.
is.na() retorna TRUE/FALSE per a cada
cel·la.NULL = objecte buit/inexistent.
is.null() retorna un únic valor per a tot l’objecte.sum(is.na(anorexia)) # nombre total de NA
## [1] 0
colSums(is.na(anorexia)) # NA per columna
## Treat Prewt Postwt
## 0 0 0
table(is.na(anorexia)) # 72 files x 3 columnes = 216 valors FALSE
##
## FALSE
## 216
is.null(anorexia)
## [1] FALSE
No hi ha cap valor perdut i l’objecte no és nul.
Recodificació de Treat. Amb
factor() indiquem els nivells originals
(levels) i les noves etiquetes (labels)
en el mateix ordre. Ho desem en una còpia
(anorexia2) per no modificar l’original, que tornarem a
usar a l’exercici 9.
levels(anorexia$Treat) # nivells originals
## [1] "CBT" "Cont" "FT"
anorexia2 <- anorexia
anorexia2$Treat <- factor(anorexia2$Treat,
levels = c("CBT", "Cont", "FT"),
labels = c("Cogn Beh Tr", "Contr", "Fam Tr"))
levels(anorexia2$Treat)
## [1] "Cogn Beh Tr" "Contr" "Fam Tr"
table(anorexia2$Treat) # quants pacients hi ha a cada tractament
##
## Cogn Beh Tr Contr Fam Tr
## 29 26 17
biopsy a .csvdata("biopsy")
head(biopsy)
write.csv(biopsy, "sortides/biopsy.csv", row.names = FALSE)
Melanoma en tres formats diferentsExportem a .csv, .txt (separat per
tabuladors) i .rds (format natiu d’R, conserva els tipus de
dades). L’Excel (.xlsx) necessitaria un paquet extra com
writexl
(writexl::write_xlsx(Melanoma, "sortides/melanoma.xlsx")).
data("Melanoma")
write.csv(Melanoma, "sortides/melanoma.csv", row.names = FALSE)
write.table(Melanoma, "sortides/melanoma.txt", sep = "\t", row.names = FALSE)
saveRDS(Melanoma, "sortides/melanoma.rds")
# Comprovem que s'han creat els fitxers i la seva mida
list.files("sortides", pattern = "melanoma", full.names = TRUE)
## [1] "sortides/melanoma.csv" "sortides/melanoma.rds" "sortides/melanoma.txt"
summary() de age desat en un
.doccapture.output() captura el text que R imprimiria a la
consola i l’escriu en un fitxer.
summary(Melanoma$age)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 4.00 42.00 54.00 52.46 65.00 95.00
capture.output(summary(Melanoma$age), file = "sortides/summary_age.doc")
file.exists("sortides/summary_age.doc")
## [1] TRUE
.csv d’un repositori de BiomedicinaExemple amb el conjunt Heart Failure Clinical Records de l’UCI (https://archive.ics.uci.edu/dataset/519/heart+failure+clinical+records).
fitxer <- "dades/heart_failure_clinical_records_dataset.csv"
if (file.exists(fitxer)) {
heart <- read_csv(fitxer, show_col_types = FALSE)
print(dim(heart))
print(head(heart))
} else {
cat("Encara no s'ha descarregat el fitxer", fitxer, "\n")
}
## [1] 299 13
## # A tibble: 6 × 13
## age anaemia creatinine_phosphokinase diabetes ejection_fraction
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 75 0 582 0 20
## 2 55 0 7861 0 38
## 3 65 0 146 0 20
## 4 50 1 111 0 20
## 5 65 1 160 1 20
## 6 90 1 47 0 40
## # ℹ 8 more variables: high_blood_pressure <dbl>, platelets <dbl>,
## # serum_creatinine <dbl>, serum_sodium <dbl>, sex <dbl>, smoking <dbl>,
## # time <dbl>, DEATH_EVENT <dbl>
birthwtdata("birthwt")
head(birthwt)
a) Edat màxima de les mares
max(birthwt$age)
## [1] 45
b) Edat mínima de les mares
min(birthwt$age)
## [1] 14
c) Rang d’edat (diferència entre màxim i mínim;
range() retorna els dos extrems)
range(birthwt$age)
## [1] 14 45
max(birthwt$age) - min(birthwt$age)
## [1] 31
d) Fumava la mare del nounat de menys pes?
Seleccionem smoke a la fila on bwt és mínim
(smoke: 1 = sí, 0 = no).
birthwt$smoke[birthwt$bwt == min(birthwt$bwt)]
## [1] 1
Sí, la mare fumava.
e) Pes del nounat de la mare amb l’edat màxima
birthwt$bwt[birthwt$age == max(birthwt$age)]
## [1] 4990
f) Pesos dels nounats les mares dels quals visiten el metge
menys de dues vegades el primer trimestre (ftv
< 2)
pesos_ftv <- birthwt$bwt[birthwt$ftv < 2]
pesos_ftv
## [1] 2523 2557 2600 2622 2637 2637 2663 2665 2722 2733 2751 2769 2769 2778 2807
## [16] 2821 2836 2863 2877 2906 2920 2920 2920 2948 2948 2977 2977 2922 3033 3062
## [31] 3062 3062 3062 3090 3090 3100 3104 3132 3175 3175 3203 3203 3203 3225 3225
## [46] 3232 3234 3260 3274 3317 3317 3331 3374 3374 3402 3416 3444 3459 3460 3473
## [61] 3544 3487 3544 3572 3572 3586 3600 3614 3614 3629 3637 3643 3651 3651 3651
## [76] 3651 3699 3728 3756 3770 3770 3770 3790 3799 3827 3884 3912 3940 3941 3941
## [91] 3969 3997 3997 4054 4054 4111 4174 4238 4593 4990 709 1135 1330 1474 1588
## [106] 1588 1701 1729 1790 1818 1885 1893 1899 1928 1936 1970 2055 2055 2084 2084
## [121] 2100 2125 2187 2187 2211 2225 2240 2240 2282 2296 2296 2325 2353 2353 2367
## [136] 2381 2381 2381 2410 2410 2410 2424 2442 2466 2466 2495 2495
length(pesos_ftv) # quants nounats compleixen la condició
## [1] 147
Prewt i Postwtmatrix() omple per columnes per defecte: si li passem
els dos vectors concatenats i ncol = 2, la primera columna
serà Prewt i la segona Postwt.
cbind() fa el mateix de manera més directa i manté els
noms.
matr_anorexia <- matrix(c(anorexia$Prewt, anorexia$Postwt), ncol = 2)
colnames(matr_anorexia) <- c("Prewt", "Postwt")
head(matr_anorexia)
## Prewt Postwt
## [1,] 80.7 80.2
## [2,] 89.4 80.1
## [3,] 91.8 86.4
## [4,] 74.0 86.3
## [5,] 78.1 76.1
## [6,] 88.3 78.1
dim(matr_anorexia) # 72 files i 2 columnes
## [1] 72 2
# Alternativa equivalent
head(cbind(Prewt = anorexia$Prewt, Postwt = anorexia$Postwt))
## Prewt Postwt
## [1,] 80.7 80.2
## [2,] 89.4 80.1
## [3,] 91.8 86.4
## [4,] 74.0 86.3
## [5,] 78.1 76.1
## [6,] 88.3 78.1
Tract_PulmoIdentificador <- c("I1","I2","I3","I4","I5","I6","I7","I8","I9","I10","I11","I12","I13",
"I14","I15","I16","I17","I18","I19","I20","I21","I22","I23","I24","I25")
Edat <- c(23,24,21,22,23,25,26,24,21,22,23,25,26,24,22,21,25,26,24,21,25,27,26,22,29)
Sexe <- c(1,2,1,1,1,2,2,2,1,2,1,2,2,2,1,1,1,2,2,2,1,2,1,1,2) # 1 dona, 2 home
Pes <- c(76.5,81.2,79.3,59.5,67.3,78.6,67.9,100.2,97.8,56.4,65.4,67.5,87.4,99.7,87.6,
93.4,65.4,73.7,85.1,61.2,54.8,103.4,65.8,71.7,85.0)
Alt <- c(165,154,178,165,164,175,182,165,178,165,158,183,184,164,189,167,182,179,165,
158,183,184,189,166,175) # altura en cm
Fuma <- c("SÍ","NO","SÍ","SÍ","NO","NO","NO","SÍ","SÍ","SÍ","NO","NO","SÍ","SÍ","SÍ",
"SÍ","NO","NO","SÍ","SÍ","SÍ","NO","SÍ","NO","SÍ")
Tract_Pulmo <- data.frame(Identificador, Edat, Sexe, Pes, Alt, Fuma)
Tract_Pulmo
Un data frame s’indexa com df[files, columnes]. Si
deixem un costat buit, vol dir “totes”.
a) Registres amb edat > 22
Tract_Pulmo[Tract_Pulmo$Edat > 22, ] # amb indexació lògica
b) Element 3 de la columna 4 (fila 3, columna 4 =
Pes)
Tract_Pulmo[3, 4]
## [1] 79.3
c) subset(): edat < 27 i sense la columna
Alt. L’argument select indica les
columnes; amb el signe - les excloem.
subset(Tract_Pulmo, Edat < 27, select = -Alt)
ChickWeighta) Incorporar el conjunt de dades del paquet
datasets (es carrega per defecte amb R):
data("ChickWeight", package = "datasets")
str(ChickWeight)
## Classes 'nfnGroupedData', 'nfGroupedData', 'groupedData' and 'data.frame': 578 obs. of 4 variables:
## $ weight: num 42 51 59 64 76 93 106 125 149 171 ...
## $ Time : num 0 2 4 6 8 10 12 14 16 18 ...
## $ Chick : Ord.factor w/ 50 levels "18"<"16"<"15"<..: 15 15 15 15 15 15 15 15 15 15 ...
## $ Diet : Factor w/ 4 levels "1","2","3","4": 1 1 1 1 1 1 1 1 1 1 ...
## - attr(*, "formula")=Class 'formula' language weight ~ Time | Chick
## .. ..- attr(*, ".Environment")=<environment: R_EmptyEnv>
## - attr(*, "outer")=Class 'formula' language ~Diet
## .. ..- attr(*, ".Environment")=<environment: R_EmptyEnv>
## - attr(*, "labels")=List of 2
## ..$ x: chr "Time"
## ..$ y: chr "Body weight"
## - attr(*, "units")=List of 2
## ..$ x: chr "(days)"
## ..$ y: chr "(gm)"
head(ChickWeight)
b) Gràfic de dispersió de weight. Amb
una sola variable, plot() posa l’índex de l’observació a
l’eix X i el valor a l’eix Y.
plot(ChickWeight$weight, col = "steelblue", pch = 20,
main = "Pes dels pollets", xlab = "Observació", ylab = "Pes (g)")
c) Diagrama de caixa de Time
boxplot(ChickWeight$Time, col = "yellow",
main = "Temps des del naixement", ylab = "Dies")
anorexia_treat_dfL’enunciat diu calcular Prewt - Postwt, però amb aquesta
resta un guany de pes dona un valor
negatiu. Per interpretar-ho més fàcilment calculem
Postwt - Prewt, de manera que valors positius = pes
guanyat.
dif_pes <- anorexia$Postwt - anorexia$Prewt
anorexia_treat_df <- data.frame(Treat = anorexia$Treat, dif_pes)
head(anorexia_treat_df)
# Individus que han guanyat pes
guanyen <- subset(anorexia_treat_df, dif_pes > 0)
nrow(guanyen)
## [1] 42
# Només els del tractament "Cont" que han guanyat pes (& = i lògic)
anorexia_treat_C_df <- subset(anorexia_treat_df, Treat == "Cont" & dif_pes > 0)
anorexia_treat_C_df
Usem set.seed() perquè els valors aleatoris siguin
sempre els mateixos (resultats reproduïbles). rep()
repeteix valors, sample() tria valors a l’atzar i
rnorm() genera valors d’una distribució normal.
set.seed(123)
n <- 30
dades <- data.frame(
Id = paste0("P", 1:n), # caràcter
Edat = sample(18:80, n, replace = TRUE), # numèrica
Gene = rep(c(1, 2), each = 15), # 1 = dona, 2 = home
Tract = factor(sample(c("A", "B", "C"), n, replace = TRUE)),# factor
Pes = round(rnorm(n, mean = 72, sd = 12), 1), # kg
Alt = round(rnorm(n, mean = 168, sd = 9)) # cm
)
head(dades)
dim(dades) # files i columnes
## [1] 30 6
str(dades) # tipus de cada variable
## 'data.frame': 30 obs. of 6 variables:
## $ Id : chr "P1" "P2" "P3" "P4" ...
## $ Edat : int 48 32 68 31 20 59 67 71 60 54 ...
## $ Gene : num 1 1 1 1 1 1 1 1 1 1 ...
## $ Tract: Factor w/ 3 levels "A","B","C": 2 3 2 1 3 3 1 3 2 1 ...
## $ Pes : num 81.9 80.3 78.6 71.3 68.3 67.4 63.7 69.5 56.8 98 ...
## $ Alt : num 158 171 172 168 176 186 164 147 177 162 ...
summary(dades) # resum estadístic
## Id Edat Gene Tract Pes
## Length:30 Min. :20.00 Min. :1.0 A:13 Min. :53.40
## Class :character 1st Qu.:31.25 1st Qu.:1.0 B: 7 1st Qu.:67.25
## Mode :character Median :45.50 Median :1.5 C:10 Median :71.40
## Mean :47.93 Mean :1.5 Mean :72.79
## 3rd Qu.:65.25 3rd Qu.:2.0 3rd Qu.:78.90
## Max. :74.00 Max. :2.0 Max. :98.00
## Alt
## Min. :147.0
## 1st Qu.:165.0
## Median :170.0
## Mean :169.0
## 3rd Qu.:173.8
## Max. :186.0
table(dades$Gene) # 15 dones i 15 homes
##
## 1 2
## 15 15
table(dades$Tract)
##
## A B C
## 13 7 10
IMC = pes (kg) / alçada (m)². Com que Alt és en cm, la
dividim per 100. Assignant a dades$IMC la columna s’afegeix
directament al data frame.
dades$IMC <- round(dades$Pes / (dades$Alt / 100)^2, 2)
head(dades)
Df_Dones <- subset(dades, Gene == 1)
Df_Homes <- subset(dades, Gene == 2)
nrow(Df_Dones)
## [1] 15
nrow(Df_Homes)
## [1] 15
head(Df_Dones)
head(Df_Homes)
rbind()rbind() uneix data frames per files (han de tenir les
mateixes columnes).
Df_Tot <- rbind(Df_Dones, Df_Homes)
dim(Df_Tot)
## [1] 30 7
identical(Df_Tot, dades) # recuperem exactament el conjunt original
## [1] TRUE