# Això és un comentari clínic: R no l'executa
tas <- 140 # pressió sistòlica basalCurs d’Estadística amb R per a Metges - Capítol 1: Introducció
1 Introducció a R
Aquest primer capítol és un crash course d’R per començar a caminar. No pretén ser una guia ortodoxa ni exhaustiva d’enginyeria de programari, sinó que explica els conceptes i el codi mínim indispensable per desenvolupar les tasques d’estadística mèdica que utilitzarem al llarg del manual.
R té desenes de formes diferents de fer exactament la mateixa operació. Al llarg d’aquest text n’explicarem gairebé sempre una de sola: la més entenedora, coherent i estandarditzada en recerca biomèdica (fonamentalment basada en l’ecosistema Tidyverse).
1.1 El llenguatge R en recerca biomèdica
En l’àmbit de les ciències de la salut, tradicionalment “fer estadística” s’ha associat a paquets comercials com SPSS, Stata o SAS. Tot i que són programes solvents, presenten tres desavantatges notables:
- Cost i llicències: Són eines privades amb quotes sovint prohibitives fora dels servidors de les institucions.
Opacitat (“caixa negra”): Fomenten una dinàmica de navegació per menús desplegables on sovint s’obté un p-valor sense entendre quins supòsits s’estan assumint ni com s’han tractat les dades.
Dificultat de reproducció: Documentar el camí exacte que s’ha seguit des del full de càlcul brut fins a la taula final és complex si s’ha fet amb clics de ratolí.
La popularitat d’R no ha parat de créixer en la comunitat científica internacional per motius clars:
1. És gratuït i de codi obert: Tothom pot auditar el codi, instal·lar-lo a qualsevol ordinador i verificar els algorismes.
2. Reproduïbilitat i ètica en recerca: L’anàlisi queda escrita en un document (script o Quarto). Si l’any vinent entren 50 pacients més a la base de dades, es reexecuta el document i totes les taules i gràfics s’actualitzen en dos segons.
3. Potència en l’era dels models de llenguatge (IA): En ser un dels llenguatges més documentats i oberts d’Internet, les eines d’intel·ligència artificial (com Gemini o Claude) generen codi d’R —i especialment de Tidyverse— amb una precisió i netedat molt superior a la de qualsevol sintaxi propietària.
R serveix per calcular un senzill test de Student, però també per analitzar big data, construir quadres de comandament clínics en temps real (Shiny), escriure tesis doctorals, generar informes automàtics o redactar aquest mateix manual.
1.2 Instal·lació d’R i RStudio. Anatomia de l’IDE. Projectes en R
R “despullat” s’executa des d’una consola de terminal fosca i poc amigable. A la pràctica, ningú treballa directament sobre la terminal pura; ho fem a través d’un IDE (Integrated Development Environment o Entorn de Desenvolupament Integrat).
L’estàndard indiscutible en el nostre àmbit és RStudio Desktop (de l’empresa Posit).
1.2.1 L’anatomia de l’espai de treball (els 4 panells)
Quan obrim RStudio ens trobem amb una pantalla dividida en quatre quadrants interconnectats:
- Editor / Script (superior esquerre): El nostre bloc de notes de treball. És on redactem el guió d’instruccions o els fitxers Quarto (
.qmd). El que escrivim aquí queda guardat al disc dur per poder-ho recuperar demà. - Consola (inferior esquerre): El motor d’execució directa. És on s’envien les ordres per ser calculades immediatament. Els resultats numèrics ràpids i els missatges del sistema apareixen aquí.
- Entorn / Environment (superior dret): La “memòria viva” de la sessió. Aquí R ens mostra les taules de dades de pacients que hem carregat, els models calculats, els vectors i les variables emmagatzemades.
- Fitxers / Plots / Viewer (inferior dret): La sortida visual. Ens permet explorar les carpetes del nostre ordinador, visualitzar els gràfics que generem (
Plots) i consultar la documentació d’ajuda (Help).
1.2.2 Què és un Projecte d’RStudio (.Rproj) i com es crea?
Treballar amb fitxers solts repartits pel disc dur és la font del 90% dels problemes de principiants (com el temut error No such file or directory).
Un Projecte d’RStudio és simplement una carpeta del teu ordinador vinculada a un fitxer amb extensió .Rproj. Quan fas doble clic a aquest fitxer: * S’obre RStudio situant automàticament aquesta carpeta com el centre de treball (working directory). * No cal escriure rutes llargues com C:/Users/Nom/Documents/.... * Si passes la carpeta sencera a un company de recerca, a ell li funcionarà exactament igual sense tocar cap ruta.
- Al menú superior d’RStudio, fes clic a File \(\rightarrow\) New Project…
- Tria New Directory (carpeta nova) \(\rightarrow\) New Project.
- Posa un nom a la carpeta (per exemple:
curs_r_trueta) i tria on desar-la (a l’Escriptori o a Documents). - Fes clic a Create Project.
- A partir d’ara, per treballar, fes sempre doble clic directament sobre el fitxer
curs_r_trueta.Rproj.
1.2.3 Què és un Script (.R) i com es treballa amb ell?
La consola s’assembla a una conversa oral: li demanes un càlcul, te’l respon i, si tanques RStudio, aquella feina s’ha perdut.
Un Script (arxiu acabat en .R) és la teva “recepta mèdica escrita”: un fitxer de text pla on guardes ordenadament totes les línies de codi del teu estudi per poder-lo desar, corregir, compartir i tornar a executar mesos després.
- Ves al menú: File \(\rightarrow\) New File \(\rightarrow\) R Script (o la drecera
Ctrl + Shift + N/Cmd + Shift + N). - S’obrirà una pestanya en blanc al panell superior esquerre anomenada
Untitled1. - Desa’l immediatament amb un nom clar: fes clic a la icona del disquet o prem
Ctrl + Si anomena’l, per exemple,01_proves.R.
1.2.3.1 Com s’executa el codi des de l’script?
No cal copiar i enganxar les línies cap a la consola: * Posa el cursor a sobre de la línia de codi que vulguis provar. * Prem la drecera clau: Ctrl + Enter (a Windows/Linux) o Cmd + Enter (a Mac). * R enviarà automàticament aquella línia a la consola, l’executarà i baixarà el cursor a la línia següent. * Si vols afegir notes explicatives que R ignori, posa sempre el símbol del coixinet (#):
.Rproj
Treballar amb fitxers solts dispersos per carpetes és la font del 90% dels errors de principiants (No such file or directory).
En obrir sempre el fitxer .Rproj de la carpeta d’estudi: * RStudio situa automàticament el directori de treball a l’arrel de la carpeta. * No cal escriure rutes llargues com C:/Users/Nom/Documents/dades/. * Totes les rutes de dades es tornen relatives i funcionaran igual a l’ordinador de la feina o al de casa.
1.3 La consola: R com a calculadora i gestió de missatges
La forma més senzilla d’entendre la consola és com una calculadora científica avançada. Escrivim una expressió, premem Enter i R en retorna el resultat:
2 + 2[1] 4
(140 - 90) / 3[1] 16.66667
sqrt(16)[1] 4
2^3[1] 8
El símbol [1] que precedeix la resposta indica simplement que el resultat comença en el primer element del vector de sortida.
Quan treballem a la consola, R ens parla a través de tres tipus de text:
* Missatge (message): Purament informatiu (per exemple, avisar quines llibreries s’han carregat). El càlcul s’ha fet sense problemes.
* Advertència (warning): El càlcul s’ha completat amb èxit, però R ens avisa que ha hagut de prendre una decisió per nosaltres (per exemple: “hi havia 3 valors buits (NA) i s’han descartat”).
* Error (error): L’execució s’ha aturat i no s’ha generat cap resultat perquè alguna instrucció està mal escrita o falta un fitxer.
1.4 Creem els primers objectes a R: Atributs i reassignació
A R, pràcticament tot és un objecte. Per guardar un valor o el resultat d’un càlcul a la memòria, fem servir l’operador d’assignació <- (format pel signe menor i un guió, que s’assembla a una fletxa cap a l’esquerra).
# Assignem valors a variables
edat <- 64
tas <- 155
# Podem operar amb els objectes directament
tas_mitjana <- tas - 10
tas_mitjana[1] 145
A RStudio, pots escriure l’operador d’assignació <- d’un sol cop prement: * Alt + - (a Windows i Linux) * Option + - (a macOS)
1.4.1 Bones pràctiques en anomenar objectes
R és sensible a les majúscules i minúscules (edat no és el mateix que Edat ni que EDAT). A l’hora de posar noms a les vostres variables i taules:
1. Eviteu espais i caràcters especials: Utilitzeu el guió baix (edat_pacient, no pas edat pacient ni edat-pacient).
2. Eviteu accents i la lletra ç/ñ: Tot i que R els tolera en versions modernes, solen donar problemes d’interpretació en canviar de sistema operatiu.
3. Noms descriptius però curts: Millor tas_ingres que tensio_arterial_sistolica_a_larribada_a_urgencies o que una lletra aïllada com x.
1.5 Funcions matemàtiques i operadors lògics
Les funcions són instruccions empaquetades que reben un o més arguments entre parèntesis i en retornen un resultat: nom_de_la_funcio(argument1, argument2).
# Arrodonir valors
round(3.141592, digits = 2)[1] 3.14
# Logaritmes i exponencials (habituals per transformar Odds Ratios o marcadors)
log(10)[1] 2.302585
exp(2.302585)[1] 9.999999
1.5.1 Operadors de comparació i lògics
Per seleccionar pacients segons criteris d’inclusió o exclusió necessitem que R avaluï condicions (retornant TRUE o FALSE):
| Operador | Significat clínic | Exemple | Resultat |
|---|---|---|---|
== |
Exactament igual a | sexe == "Dona" |
Comparació d’igualtat |
!= |
Diferent de | estadi != "IV" |
Descarta el valor |
>, < |
Més gran / Més petit que | edat >= 65 |
Criteri d’edat |
& |
I lògic (totes dues certes) | edat > 65 & hta == "Sí" |
Pacient d’edat amb HTA |
\| |
O lògic (com a mínim una certa) | diabetis == "Sí" \| hta == "Sí" |
Risc cardiovascular present |
%in% |
Dins d’un llistat de valors | diagnostic %in% c("IAM", "Angina") |
Filtre múltiple |
Per comparar si una variable val quelcom, s’ha d’escriure sempre == (dos iguals). Si poseu un sol =, R intentarà assignar el valor en lloc de contrastar-lo i us donarà un error o alterarà la dada.
1.6 Estructures de dades: Vectors i Dataframes
En recerca biomèdica treballem bàsicament amb dues estructures:
1.6.1 El vector: La columna d’una variable
Un vector és una col·lecció unidimensional d’elements del mateix tipus. Es construeix amb la funció de combinar c():
troponina <- c(12, 45, 120, 8, 350)
troponina[1] 12 45 120 8 350
1.6.2 El Dataframe (o Tibble): La història clínica rectangular
Un dataframe és una taula bidimensional que agrupa múltiples vectors de la mateixa longitud. És l’equivalent digital al full de dades d’Excel, però subjecte a les regles de les dades netes (tidy data): * Cada fila representa una observació única (un pacient). * Cada columna representa una variable clínica mesurada.
# Creació d'una petita base de dades clínica
pacients <- data.frame(
id = 1:4,
edat = c(58, 72, 63, 81),
sexe = c("Home", "Dona", "Home", "Dona"),
exitus = c(FALSE, TRUE, FALSE, FALSE)
)
pacients id edat sexe exitus
1 1 58 Home FALSE
2 2 72 Dona TRUE
3 3 63 Home FALSE
4 4 81 Dona FALSE
Podem extreure una columna aïllada d’un dataframe fent servir el símbol del dòlar $:
pacients$edat[1] 58 72 63 81
mean(pacients$edat)[1] 68.5
1.7 Tipus de dades (datatypes) i coerció
R assigna automàticament un tipus de dada a cada columna. Els quatre tipus clínics essencials són:
- Numèric (
numeric/double/integer): Valors continus o enters (edat, filtrat glomerular, tensió arterial). - Text (
character): Paraules o cadenes de caràcters tancades entre cometes ("Home","Cardiopatia isquèmica"). - Lògic (
logical): Valors booleans binaris (TRUEoFALSE). - Factor (
factor): Variables categòriques amb nivells prefixats (levels). És fonamental per a variables clíniques qualitatives ordinals o nominals (com ara l’estadi funcional NYHA: I, II, III, IV), ja que permet establir quin és el grup de referència per als models de regressió.
# Convertim la variable sexe en factor especificant categories
pacients$sexe <- factor(pacients$sexe, levels = c("Home", "Dona"))
class(pacients$sexe)[1] "factor"
levels(pacients$sexe)[1] "Home" "Dona"
R exigeix que tots els elements d’una mateixa columna siguin del mateix tipus. Si en una columna numèrica de glucèmies algú ha escrit a l’Excel "pendent" o "sense mostra", R convertirà tota la columna a text.
Quan intenteu calcular mean(dades$glucemia), R us dirà: argument is not numeric or logical: returning NA.
::::::
1.8 Paquets, llibreries i funcions
Quan instal·lem R disposem d’una dotació bàsica d’eines (R base). La veritable força de la comunitat científica, però, resideix en els paquets (packages): mòduls amb funcions especialitzades desenvolupades per altres investigadors i publicades al repositori oficial CRAN.
- Instal·lar un paquet (
install.packages("nom")): Equival a comprar una bombeta a la botiga i caragolar-la a la làmpada. Només es fa un sol cop a la vida per a cada ordinador. - Carregar una llibreria (
library(nom)): Equival a prémer l’interruptor per encendre el llum. S’ha de fer cada vegada que obrim una nova sessió d’R o al principi de cada fitxer d’anàlisi.
# S'instal·la una sola vegada des de la consola (ull a les cometes!):
install.packages("tidyverse")
install.packages("readxl")# Es carrega a l'inici de cada script (sense cometes):
library(tidyverse)
library(readxl)Si executeu una ordre com read_excel() o filter() i R us respon: Error in read_excel(...) : could not find function "read_excel" El motiu és sempre que heu oblidat executar la línia library(...) corresponent al principi de la sessió.
1.9 Dades d’entrenament a R
Un dels grans avantatges didàctics d’R és que incorpora conjunts de dades clíniques i científiques preinstal·lats llestos per practicar sense haver de descarregar cap fitxer extern.
Alguns exemples clàssics disponibles directament: * iris: Dades biomètriques clàssiques de botànica. * mtcars: Proves de rendiment de vehicles de motor. * Dades del Titanic (Titanic o via paquets docents). Per veure tots els que venen carregats amb rbase feu a la consola data(). Despres els podeu veure directament escrivint el nom o amb View()per exemple.
# Visualitzem les primeres línies d'un dataset intern
head(iris, n = 4) Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
View(women)1.10 Importació de dades: Excel, CSV, SPSS i Stata
A la pràctica hospitalària, el 95% de les dades de recerca arriben en formats d’altres programes.
1.10.1 Fitxers de text pla (.csv)
És el format més universal i estable per a recerca:
# Amb Tidyverse (readr):
dades <- read_csv("data/pacients.csv")
# Si el CSV prové d'un sistema europeu/català on els decimals són comes (,) i els separadors són punts i comes (;):
dades <- read_csv2("data/pacients_excel.csv")1.10.2 Fulls de càlcul d’Excel (.xlsx, .xls)
Gràcies al paquet readxl:
library(readxl)
# Llegeix el primer full per defecte
dades_excel <- read_excel("data/registre_clinica.xlsx")
# Si volem triar un full concret del fitxer:
dades_excel <- read_excel("data/registre_clinica.xlsx", sheet = "UCI")1.10.3 Altres programes estadístics (SPSS, Stata, SAS)
El paquet haven permet importar arxius privatius preservant fins i tot les etiquetes originals:
library(haven)
# Fitxer d'SPSS (.sav)
dades_spss <- read_sav("data/estudi.sav")Fixeu-vos que la ruta sempre comença amb un nom relatiu com "data/pacients.csv" o "titanic.csv".
Com que treballem dins d’un Projecte d’RStudio (.Rproj), R busca automàticament a partir de la carpeta del projecte. No cal escriure camins absoluts personals com C:/Users/pablo/Documents/..., que fallarien en compartir el codi amb un altre company.
1.11 R base vs. Tidyverse: El salt de llegibilitat
Per fer una mateixa transformació de dades, a R hi ha dues filosofies: 1. R base: Sintaxi clàssica, sovint plena de claudàtors imbricats [ ] i funcions acumulades de dins cap a fora, difícil de llegir per a qui no és programador. 2. Tidyverse: Un dialecte modern dissenyat per humans on el codi s’escriu d’esquerra a dreta, seguint el fil del pensament clínic.
1.11.1 L’operador de canonada (pipe): %>% o |>
La “canonada” agafa el resultat de l’operació anterior i el passa com a primer argument a la funció següent. Es llegeix com: “…i després fes…”.
Imaginem un cas clínic: volem agafar el registre de pacients, filtrar els més grans de 65 anys i seleccionar només el seu identificador i la troponina:
Forma clàssica (R base - difícil de llegir):
# Llegit de dins cap a fora:
dades_subgrup <- dades[dades$edat > 65, c("id", "troponina")]Forma moderna (Tidyverse - seqüència clínica natural):
dades_subgrup <- dades %>%
filter(edat > 65) %>%
select(id, troponina)La sintaxi Tidyverse no només és més intuïtiva per als professionals de la salut, sinó que és exactament el patró que els models d’intel·ligència artificial generen amb més fiabilitat i claredat.
1.12 Cercant ajuda i la IA com a copilot crític
Un dels principis de la recerca amb R és que ningú memoritza totes les opcions de totes les funcions. Saber com documentar-se i resoldre errors és la competència més útil a llarg termini.
1.12.1 L’ajuda integrada d’R
Davant de qualsevol funció desconeguda, només cal escriure un signe d’interrogant (?) seguit del nom de la comanda a la consola:
?mean
?read_csvS’obrirà la documentació oficial al panell inferior dret (Help), on sempre trobareu la mateixa estructura: 1. Description: Breu resum del propòsit de la funció. 2. Usage: Com s’escriu la funció i quins arguments espera. 3. Arguments: Descripció detallada de cada paràmetre. 4. Examples: Exemples de codi a punt per copiar i provar.
1.12.2 La IA com a assistent d’aprenentatge: El mètode estructurat
Els models de llenguatge (com Gemini, ChatGPT o Claude) són excel·lents generant codi d’R i explicant missatges d’error. No obstant això, si es fan preguntes generals o imprecises, la IA acostuma a assumir dades que no existeixen o a inventar-se noms de variables.
- Dóna-li l’estructura real: Mai li demanis codi sense abans ensenyar-li què té la teva taula. Executa
glimpse(les_teves_dades)a la consola d’R i copia el resultat al xat. - Explicita el dialecte: Especifica sempre: “Escriu el codi exclusivament amb R i Tidyverse”. Si no, et barrejarà codi obsolet d’R base amb sintaxi moderna.
- Retorna-li els errors complets: Si un bloc de codi falla, copia exactament la línia d’error en vermell que t’ha donat la consola.
- Audita el resultat: Pregunta’t sempre: Té sentit clínic aquesta sortida? El número total de pacients coincideix?
1.12.2.1 Exemple de prompt clínic eficaç:
“Sóc investigador mèdic i estic analitzant una cohort clínica a RStudio utilitzant Tidyverse.
Aquest és el resultat de fer
glimpse(pacients):Rows: 150 Columns: 4 $ id <int> 1, 2, 3... $ edat <dbl> 64, 72, 58... $ sexe <fct> Home, Dona, Home... $ complicacio <fct> No, Sí, No...Objectiu: Genera un script per comprovar si hi ha diferències d’edat segons la presència de complicacions, mostrant mitjana i desviació típica per grup, i comprova els supòsits d’aplicació.”
1.13 Exercicis pràctics del Capítol 1
Posa en pràctica els conceptes treballats amb el teu propi script (.R):
1.13.1 Exercici 1: Gestió de variables i operadors
- Crea un objecte anomenat
pes_kgamb el valor78i un altre anomenattalla_mamb el valor1.75. - Calcula l’índex de massa corporal (\(IMC = \frac{pes}{talla^2}\)) i desa el resultat a l’objecte
imc. - Arrodoneix el resultat a un sol decimal amb la funció
round(). - Avalua amb un operador lògic si aquest pacient té un \(IMC \ge 25\) (sobrepès).
1.13.2 Exercici 2: Treballant amb vectors clínics
- Construeix un vector anomenat
tasque contingui les pressions arterials sistòliques de 5 pacients:120, 145, 160, 115, 138. - Calcula la mitjana (
mean()) i la desviació típica (sd()) d’aquest vector. - Esbrina quants pacients tenen una \(TAS \ge 140\) avaluant la condició lògica.
1.13.3 Exercici 3: El primer dataframe
- Construeix un petit dataframe de recerca anomenat
estudiamb les següents 3 columnes:id: valors de l’1 al 4.tractament: factor amb dos nivells (“Control”, “Fàrmac”).pressio: valors135, 122, 140, 118.
- Mostra la informació general de la taula fent servir
glimpse(estudi)(recorda carregarlibrary(tidyverse)prèviament). - Selecciona únicament els pacients assignats al grup “Fàrmac” utilitzant la funció
filter().
1.13.4 Exercici 4: Crear un full d’Excel i importar-lo
Aquest exercici reprodueix exactament el flux habitual a la pràctica clínica diària: 1. Obre el teu programa de fulls de càlcul (Excel, LibreOffice Calc o Google Sheets). 2. Construeix una taula petita de 4 pacients amb les següents columnes:
* id: 1, 2, 3, 4
* edat: 55, 68, 49, 73
* sexe: Dona, Home, Dona, Home
* colesterol_total: 210, 185, 240, 195
3.Guarda el document amb el nom pacients_prova.xlsx dins de la subcarpeta data del teu projecte (si no tens la carpeta data, crea-la abans).
4. Obre el teu script d’R i carrega la llibreria readxl.
5. Importa el fitxer amb la funció read_excel() guardant-lo en un objecte anomenat dades_cliniques.
6. Comprova l’estructura de la taula importada amb glimpse() i calcula la mitjana de la columna colesterol_total.
library(tidyverse)
library(readxl)
# Exercici 1
pes_kg <- 78
talla_m <- 1.75
imc <- pes_kg / (talla_m^2)
imc_arrodonit <- round(imc, digits = 1)
imc_arrodonit[1] 25.5
imc_arrodonit >= 25[1] TRUE
# Exercici 2
tas <- c(120, 145, 160, 115, 138)
mean(tas)[1] 135.6
sd(tas)[1] 18.4201
tas >= 140[1] FALSE TRUE TRUE FALSE FALSE
# Exercici 3
estudi <- tibble(
id = 1:4,
tractament = factor(c("Control", "Fàrmac", "Control", "Fàrmac")),
pressio = c(135, 122, 140, 118)
)
glimpse(estudi)Rows: 4
Columns: 3
$ id <int> 1, 2, 3, 4
$ tractament <fct> Control, Fàrmac, Control, Fàrmac
$ pressio <dbl> 135, 122, 140, 118
estudi %>%
filter(tractament == "Fàrmac")# A tibble: 2 × 3
id tractament pressio
<int> <fct> <dbl>
1 2 Fàrmac 122
2 4 Fàrmac 118
# Exercici 4
# (Aquest codi s'executa un cop creat el fitxer Excel a la subcarpeta data/)
dades_cliniques <- read_excel("data/pacients_prova.xlsx")
glimpse(dades_cliniques)
mean(dades_cliniques$colesterol_total, na.rm = TRUE)2 Exercici 4
3 (Assegura’t d’haver desat prèviament l’arxiu pacients_prova.xlsx dins de la carpeta data/)
#| eval: false dades_cliniques <- read_excel(“data/pacients_prova.xlsx”)
glimpse(dades_cliniques)
mean(dades_cliniques$colesterol_total, na.rm = TRUE) ```