Enlace web: https://rpubs.com/daniloceschin/Rbioinfo-modulo2
Asignatura: Bioinformática
Carrera: Licenciatura en Genética
Institución: IUCBC – CIMETSA, Córdoba, Argentina
Docente: Dr. Danilo G. Ceschin
Principio fundamental: En R, todo objeto tiene un tipo (qué clase de datos contiene) y una estructura (cómo están organizados esos datos). Antes de cargar tu primer archivo FASTA, VCF, BED o tabla de anotación, necesitás entender cómo R representa la información internamente. Las estructuras que veremos acá son la base de absolutamente todo lo que harás en bioinformática con R.
R tiene 4 tipos atómicos esenciales. Aparecen en cualquier dominio de la bioinformática: genómica, filogenética, proteómica, análisis de variantes, etc.
numeric — Datos cuantitativos# Valores que aparecen en distintos contextos bioinformáticos
longitud_gen <- 3426.0 # pares de bases
gc_content <- 0.523 # fracción GC
e_value <- 2.4e-87 # E-value de BLAST
distancia_gen <- 0.142 # distancia evolutiva (Kimura)
cobertura <- 42.7 # coverage promedio de secuenciación
score_calidad <- 38.0 # Phred quality score
# Verificación de tipo
is.numeric(gc_content) # TRUE
class(gc_content) # "numeric"
typeof(gc_content) # "double" (doble precisión)
# Integer — eficiente para conteos y posiciones genómicas
posicion_inicio <- 43044295L # posición en el cromosoma (cromosoma 17)
n_snps <- 4721L
is.integer(posicion_inicio) # TRUE
# Valores especiales que aparecen en bioinformática
Inf # -log10(0) en p-valores de GWAS
NaN # 0/0 al calcular razones
NA_real_ # dato faltante numérico
log10(0) # -Inf — frecuente en volcano plots
character — Identificadores y secuencias# Identificadores biológicos — la moneda corriente en bioinformática
gen_id <- "ENSG00000012048" # Ensembl gene ID
transcripto <- "ENST00000357654" # Ensembl transcript ID
proteina <- "P38398" # UniProt accession
snp_id <- "rs80357382" # dbSNP rsID
go_term <- "GO:0006281" # Gene Ontology term
organismo <- "Homo sapiens"
cromosoma <- "chr17"
genbank_id <- "NM_007294.4"
# Secuencias — character de largo variable
seq_dna <- "ATGCGATCGATCGGCTAA"
seq_prot <- "MPIGSKERPTFFEIFKTRCNKADLTHSQISLNSS"
motivo <- "TATAAA" # TATA box
# Operaciones frecuentes en bioinformática
nchar(seq_dna) # 18 — longitud de secuencia
nchar(seq_prot) # 34 — número de aminoácidos
toupper("atgcgatcg") # "ATGCGATCG" — normalizar mayúsculas
substr(seq_dna, 1, 3) # "ATG" — codón de inicio
# Extraer partes de identificadores compuestos
strsplit("chr17:43044295-43125483", "[:-]")[[1]]
# "chr17" "43044295" "43125483"
# Expresiones regulares — esenciales para parsear archivos genómicos
ids <- c("ENSG00000012048", "TP53", "ENST00000357654", "P38398")
grepl("^ENSG", ids) # T F F F — filtrar Ensembl gene IDs
grepl("^ENST", ids) # F F T F — filtrar Ensembl transcript IDs
gsub("chr", "", c("chr1","chr17","chrX")) # "1" "17" "X"
# Limpiar versiones de IDs
sub("\\.\\d+$", "", "ENSG00000012048.5") # "ENSG00000012048"
logical — Booleanos para filtros y seleccionestiene_dominio_pfam <- TRUE
es_pseudogen <- FALSE
anotado_en_omim <- NA # Not Available — distinto de FALSE
# Operadores
TRUE & FALSE # AND → FALSE
TRUE | FALSE # OR → TRUE
!TRUE # NOT → FALSE
# Casos de uso típicos en bioinformática
e_values <- c(2.4e-87, 0.003, 1.2e-45, 0.18, 8.9e-12)
identidad <- c(98.2, 45.1, 87.6, 32.0, 72.3) # % identidad BLAST
# Hits significativos de BLAST: E-value < 1e-10 Y identidad > 70%
hit_significativo <- e_values < 1e-10 & identidad > 70
hit_significativo # TRUE FALSE TRUE FALSE TRUE
which(hit_significativo) # 1 3 5 ← posiciones
sum(hit_significativo) # 3 ← cuántos hits
# NA se propaga — importante al trabajar con datos faltantes
NA & TRUE # NA
NA | TRUE # TRUE ← excepción: TRUE prevalece
is.na(NA) # TRUE ← forma correcta de detectar NA
factor — Variables categóricas con nivelesEl tipo más crítico para diseños experimentales. En bioinformática aparece en prácticamente todo análisis comparativo.
# Diseño experimental típico en genética
condicion <- factor(
c("WT","KO","WT","KO","WT","KO"),
levels = c("WT","KO") # WT = referencia
)
condicion
# [1] WT KO WT KO WT KO
# Levels: WT KO
# Otros usos frecuentes en bioinformática
# Tipo de variante
tipo_var <- factor(
c("SNP","INDEL","SNP","SNV","INDEL","SNP"),
levels = c("SNP","SNV","INDEL")
)
# Clasificación taxonómica
reino <- factor(
c("Bacteria","Eukaryota","Bacteria","Archaea","Eukaryota"),
levels = c("Bacteria","Archaea","Eukaryota")
)
# Calidad de secuencia (factor ordenado)
calidad <- factor(
c("Alta","Media","Baja","Alta","Media"),
levels = c("Baja","Media","Alta"),
ordered = TRUE
)
calidad > "Media" # FALSE FALSE TRUE FALSE FALSE
# Inspección
levels(condicion) # "WT" "KO"
nlevels(condicion) # 2
table(condicion) # WT KO → 3 3
⚠️ Regla práctica: Siempre definí los niveles de un factor explícitamente. El orden alfabético por default puede poner el grupo equivocado como referencia en cualquier análisis estadístico comparativo — no solo en RNA-seq, sino en GWAS, análisis de variantes, modelos de selección, etc.
Cuando R mezcla tipos distintos en un mismo contenedor, convierte al tipo más general:
logical → integer → numeric → complex → character
(más restrictivo) (más general)
# Coerción implícita
c(TRUE, 1L, 2L) # integer: 1 1 2
c(TRUE, 1.5, 2.0) # numeric: 1.0 1.5 2.0
c(1, 2, "BRCA1") # character: "1" "2" "BRCA1"
# Coerción explícita — la forma controlada
as.numeric("0.523") # 0.523 ✓ (GC content leído como texto)
as.integer("4721") # 4721 ✓ (n_SNPs leído como texto)
as.character(43044295L) # "43044295"
as.logical(0) # FALSE
as.logical(1) # TRUE
# ⚠️ Conversión fallida → NA silencioso
as.numeric("n/a") # NA + Warning
as.numeric("1,5") # NA ← coma decimal (frecuente en planillas europeas)
as.integer("chr17") # NA + Warning
# Detectar el problema
anotacion_raw <- c("0.89", "0.72", "N/D", "0.91", "<0.01")
valores <- as.numeric(anotacion_raw)
# Warning: NAs introduced
sum(is.na(valores)) # 2 ← cuántos no pudieron convertirse
anotacion_raw[is.na(valores)] # "N/D" "<0.01" ← cuáles son
🔬 Situación frecuente: Al parsear archivos de anotación (GFF, GTF, VCF, resultados de BLAST), columnas numéricas como e-values, scores o coordenadas a veces vienen como
character. Siempre verificá constr()al cargar datos y convertí explícitamente.
Un vector es una secuencia ordenada de elementos del mismo tipo. Es la estructura más básica de R — incluso un valor único es un vector de longitud 1. Toda la arquitectura del lenguaje está construida sobre vectores.
# Identificadores
genes <- c("BRCA1","TP53","EGFR","MYC","PTEN")
cromosomas <- c("chr17","chr17","chr7","chr8","chr10")
rsids <- c("rs80357382","rs28934578","rs121913254")
# Coordenadas genómicas
posiciones <- c(43044295L, 43045802L, 43047643L, 43049120L)
longitudes <- c(1200L, 850L, 2340L, 560L)
# Valores numéricos
gc_content <- c(0.52, 0.61, 0.48, 0.55, 0.49)
e_values <- c(2.4e-87, 8.1e-45, 1.2e-92, 3.3e-61, 5.7e-38)
identidades <- c(98.2, 87.6, 99.1, 92.4, 85.3) # % identidad
# Secuencias cortas
codones <- c("ATG","GCC","TAC","AGT","TGA") # codón de inicio, AAs, stop
# Secuencias numéricas — útiles en bioinformática
seq(1, 1000, by = 10) # posiciones en ventanas deslizantes
seq(0, 1, length.out = 11) # escala de grises para heatmap
rep(c("Caso","Control"), each=5) # replicar grupos
# Nombrar elementos — muy útil para no depender de posiciones
names(gc_content) <- genes
gc_content["BRCA1"] # 0.52
Sin bucles for — R opera sobre todos los elementos
simultáneamente:
gc_content <- c(0.52, 0.61, 0.48, 0.55, 0.49)
e_values <- c(2.4e-87, 8.1e-45, 1.2e-92, 3.3e-61, 5.7e-38)
identidades <- c(98.2, 87.6, 99.1, 92.4, 85.3)
# Transformaciones elemento a elemento
-log10(e_values) # transformación estándar para visualización
round(gc_content * 100, 1) # GC% redondeado: 52.0 61.0 ...
longitudes_kb <- longitudes / 1000 # convertir pb a kb
# Estadísticos
mean(gc_content) # 0.53
median(identidades) # 92.4
sd(gc_content) # 0.049
range(e_values) # 1.2e-92 8.1e-45
# Comparaciones → vector lógico
e_values < 1e-50 # T F T F F
identidades >= 90 # T F T T F
# hits buenos: E-value < 1e-50 Y identidad >= 90%
buenos <- e_values < 1e-50 & identidades >= 90
which(buenos) # posiciones
sum(buenos) # cantidad
# Ordenar — frecuente al rankear resultados de BLAST, GWAS, etc.
order(e_values) # índices de menor a mayor
e_values[order(e_values)] # e-values ordenados
genes[order(e_values)] # genes ordenados por e-value
sort(-log10(e_values), decreasing=TRUE) # ranking por significancia
genes <- c("BRCA1","TP53","EGFR","MYC","PTEN")
e_values <- c(2.4e-87, 8.1e-45, 1.2e-92, 3.3e-61, 5.7e-38)
identidades <- c(98.2, 87.6, 99.1, 92.4, 85.3)
names(e_values) <- genes
# Por posición (índices desde 1, no desde 0)
e_values[1] # BRCA1: 2.4e-87
e_values[c(1,3)] # BRCA1 y EGFR
e_values[-2] # todos excepto TP53
e_values[1:3]
# Por nombre
e_values["BRCA1"]
e_values[c("TP53","MYC")]
# Por condición lógica (el más usado)
e_values[e_values < 1e-50]
genes[identidades >= 90] # genes con buena identidad
genes[e_values < 1e-50 & identidades >= 90] # hits de calidad
# Modificar
e_values["PTEN"] <- 3.1e-42
e_values[is.na(e_values)] <- 1 # reemplazar NA con valor por default
El data frame es la estructura más usada en bioinformática aplicada. Es equivalente a una tabla 2D donde cada fila es una observación (gen, variante, secuencia, muestra, especie) y cada columna es un atributo.
Características clave: - Cada columna puede ser de diferente tipo - Todas las columnas tienen el mismo largo - Es el formato nativo de tablas de anotación, resultados de BLAST, tablas de variantes, metadatos de muestras, etc.
# Tabla de anotación de genes — data.frame típico en bioinformática
anotacion <- data.frame(
gene_id = c("ENSG00000012048","ENSG00000141510","ENSG00000146648",
"ENSG00000136997","ENSG00000171862"),
symbol = c("BRCA1","TP53","EGFR","MYC","PTEN"),
chr = c("chr17","chr17","chr7","chr8","chr10"),
inicio = c(43044295L, 7668402L, 55019017L, 127735434L, 89692905L),
fin = c(43125483L, 7687550L, 55211628L, 127741434L, 89728532L),
hebra = c("-","-","+","+","+"),
biotype = factor(c("protein_coding","protein_coding","protein_coding",
"protein_coding","protein_coding")),
stringsAsFactors = FALSE
)
# Calcular longitud del gen como columna derivada
anotacion$longitud_pb <- anotacion$fin - anotacion$inicio
# Cargar desde archivo (los formatos más comunes en bioinformática)
# CSV / TSV genérico
anotacion <- read.csv("annotation.csv", stringsAsFactors = FALSE)
blast_hits <- read.table("blast_results.txt", header=TRUE, sep="\t",
stringsAsFactors = FALSE)
# Archivos con comentarios (como VCF o GFF simplificados)
variantes <- read.table("variantes.tsv", header=TRUE, sep="\t",
comment.char="#", stringsAsFactors=FALSE)
# Con readr (más robusto)
library(readr)
blast_hits <- read_tsv("blast_results.txt",
col_types = cols(evalue = col_double(),
pident = col_double()))
dim(anotacion) # c(filas, columnas)
nrow(anotacion) # número de genes/variantes/secuencias
ncol(anotacion) # número de atributos
head(anotacion) # primeras 6 filas
View(anotacion) # visor interactivo en RStudio
# *** Fundamental: verificar que los tipos son correctos ***
str(anotacion)
# 'data.frame': 5 obs. of 8 variables:
# $ gene_id : chr "ENSG00000012048" ...
# $ symbol : chr "BRCA1" ...
# $ chr : chr "chr17" ...
# $ inicio : int 43044295 7668402 ...
# $ fin : int 43125483 7687550 ...
# $ hebra : chr "-" "-" ...
# $ biotype : Factor w/ 1 level "protein_coding": 1 1 ...
# $ longitud_pb: int 81188 19148 ...
summary(anotacion)
# Columna → vector
anotacion$symbol
anotacion[["longitud_pb"]] # equivalente
# Fila → data.frame de 1 fila
anotacion[1, ]
anotacion[anotacion$symbol == "BRCA1", ]
# Filtros típicos en bioinformática
# Genes en un cromosoma específico
chr17_genes <- anotacion[anotacion$chr == "chr17", ]
# Genes largos (> 50 kb)
genes_largos <- subset(anotacion, longitud_pb > 50000,
select = c(symbol, chr, longitud_pb))
# Con dplyr (sintaxis más legible)
library(dplyr)
anotacion |>
filter(chr == "chr17", longitud_pb > 10000) |>
select(symbol, inicio, fin, longitud_pb) |>
arrange(desc(longitud_pb))
# Resumen por cromosoma
anotacion |>
group_by(chr) |>
summarise(
n_genes = n(),
longitud_media = mean(longitud_pb),
longitud_max = max(longitud_pb)
)
# Unir tablas — fundamental al integrar resultados con anotación
# Equivalente a JOIN (SQL) o VLOOKUP (Excel)
blast_hits <- data.frame(
query_id = c("seq_001","seq_002","seq_003"),
subject = c("ENSG00000012048","ENSG00000141510","ENSG00000146648"),
pident = c(98.2, 87.6, 99.1),
evalue = c(2.4e-87, 8.1e-45, 1.2e-92)
)
# Agregar anotación a los hits de BLAST
blast_anotado <- merge(blast_hits, anotacion,
by.x = "subject", by.y = "gene_id",
all.x = TRUE)
# Con dplyr:
blast_anotado <- left_join(blast_hits, anotacion,
by = c("subject" = "gene_id"))
📋 tibble vs data.frame: Los paquetes del tidyverse y muchos paquetes modernos devuelven
tibble— una versión mejorada con mejor impresión. Son intercambiables en la mayoría de los casos; convertir conas.data.frame()si un paquete antiguo lo requiere.
La matriz es la estructura central de los análisis cuantitativos en bioinformática: alineamientos múltiples, matrices de distancia, perfiles de binding, datos de microarray, frecuencias alélicas, etc.
Diferencia clave con data.frame: todos los elementos
deben ser del mismo tipo, casi siempre
numeric.
# ── Caso 1: Matriz de distancias evolutivas ──────────────────────────────────
# (output típico de dist.dna() de ape, dist() o muscle + análisis filogenético)
especies <- c("H.sapiens","P.troglodytes","G.gorilla","P.pygmaeus","M.mulatta")
distancias <- matrix(
c(0.000, 0.012, 0.015, 0.028, 0.071,
0.012, 0.000, 0.014, 0.027, 0.070,
0.015, 0.014, 0.000, 0.029, 0.072,
0.028, 0.027, 0.029, 0.000, 0.074,
0.071, 0.070, 0.072, 0.074, 0.000),
nrow = 5, byrow = TRUE,
dimnames = list(especies, especies)
)
distancias["H.sapiens", "P.troglodytes"] # 0.012
# ── Caso 2: Matriz de frecuencias alélicas (datos poblacionales) ─────────────
poblaciones <- c("AFR","EUR","EAS","AMR","SAS")
snps <- paste0("rs", c(334, 1799945, 2230021, 4988235))
freq_mat <- matrix(
c(0.19, 0.48, 0.04, 0.31, 0.26, # rs334 (HBB — malaria resistance)
0.00, 0.01, 0.00, 0.00, 0.00, # rs1799945 (HFE)
0.75, 0.65, 0.89, 0.72, 0.70, # rs2230021
0.45, 0.52, 0.38, 0.47, 0.50), # rs4988235 (lactasa)
nrow = 4, byrow = TRUE,
dimnames = list(snps, poblaciones)
)
# ── Caso 3: Matriz de scores de alineamiento ─────────────────────────────────
secuencias <- c("seq_A","seq_B","seq_C","seq_D")
scores_ali <- matrix(
c(100, 85, 62, 41,
85, 100, 58, 39,
62, 58, 100, 71,
41, 39, 71, 100),
nrow = 4,
dimnames = list(secuencias, secuencias)
)
# Acceso
freq_mat["rs334", ] # frecuencias de rs334 en todas las pops
freq_mat[, "EUR"] # todos los SNPs en europeos
freq_mat["rs334", "AFR"] # valor puntual
freq_mat[1:2, c("AFR","EUR")] # submatriz
# Operaciones por filas/columnas
rowMeans(freq_mat) # frecuencia media de cada SNP
colMeans(freq_mat) # frecuencia media en cada población
apply(freq_mat, 1, var) # variabilidad de cada SNP entre poblaciones
apply(freq_mat, 2, sd) # variabilidad entre SNPs en cada población
# Transponer — muy usado
t(freq_mat) # ahora: poblaciones × SNPs
# Álgebra lineal
cor(t(freq_mat)) # correlación entre poblaciones
dist(freq_mat) # distancias euclídeas entre SNPs
library(pheatmap)
# Heatmap de frecuencias alélicas por población
pheatmap(
mat = freq_mat,
color = colorRampPalette(c("white","#0A7EA4","navy"))(50),
display_numbers = TRUE, # mostrar valores en las celdas
number_format = "%.2f",
cluster_rows = TRUE, # agrupar SNPs por perfil similar
cluster_cols = TRUE, # agrupar poblaciones por perfil similar
main = "Frecuencias alélicas por población"
)
# Heatmap de matriz de distancias evolutivas
pheatmap(
mat = distancias,
color = colorRampPalette(c("white","#F5A623","#0D1F3C"))(50),
display_numbers = TRUE,
main = "Distancias evolutivas entre primates (Kimura 2P)"
)
🧬 En Bioconductor: Muchas clases S4 tienen matrices como componente central.
DNAStringSetde Biostrings almacena múltiples secuencias.GRangesde GenomicRanges maneja coordenadas.SummarizedExperimentenvuelve una matriz de datos junto a metadatos de filas y columnas en un objeto validado.
La lista es el contenedor más flexible de R: puede almacenar objetos de cualquier tipo y tamaño. Es la estructura que usan internamente casi todos los resultados estadísticos y los objetos de Bioconductor.
# Lista de metadatos de una secuencia / experimento de secuenciación
registro_sec <- list(
accession = "NM_007294.4",
organismo = "Homo sapiens",
gen = "BRCA1",
longitud_pb = 7088L,
cromosoma = "chr17",
coordenadas = c(43044295L, 43125483L),
hebra = "-",
exones = 23L,
secuencia = "ATGCGATCGATCG...", # secuencia completa
dominios = data.frame( # data.frame anidado
nombre = c("RING","BRCT_1","BRCT_2"),
inicio = c(1L, 1646L, 1755L),
fin = c(109L, 1736L, 1855L)
),
referencias = list(
pmid_original = "7545954",
pmid_estructura = "8493562"
)
)
str(registro_sec) # ver estructura completa
length(registro_sec)
names(registro_sec)
# $ — acceso por nombre (más legible, más usado)
registro_sec$accession # "NM_007294.4"
registro_sec$coordenadas # c(43044295, 43125483)
registro_sec$dominios # el data.frame completo
# [[ ]] — por nombre o posición
registro_sec[["longitud_pb"]] # 7088
registro_sec[[4]] # 7088 (por posición)
# Acceso con nombre guardado en variable ($ no puede hacer esto)
campo <- "gen"
registro_sec[[campo]] # "BRCA1"
# [ ] — extrae sublista (mantiene tipo lista)
registro_sec["accession"] # lista de 1 elemento — sigue siendo lista
class(registro_sec["accession"]) # "list"
class(registro_sec[["accession"]]) # "character" ← diferencia crítica
# Acceso anidado
registro_sec$dominios$nombre # c("RING","BRCT_1","BRCT_2")
registro_sec$referencias$pmid_original # "7545954"
# Ejemplo: comparación de GC content entre regiones codificantes y no codificantes
gc_coding <- c(0.54, 0.58, 0.52, 0.56, 0.51, 0.55)
gc_noncoding <- c(0.41, 0.38, 0.44, 0.40, 0.42, 0.39)
res <- t.test(gc_coding, gc_noncoding)
# Ver la estructura completa del resultado
str(res) # es una lista S3 con 9 elementos
names(res) # "statistic" "parameter" "p.value" "conf.int" etc.
# Extraer elementos clave
res$statistic # t = 8.27
res$p.value # 1.2e-05
res$conf.int # [0.10, 0.17]
res$estimate # mean_coding=0.543, mean_noncoding=0.407
# Patrón frecuente: múltiples tests sobre una lista de objetos
secuencias <- list(
exon1 = c(0.54, 0.58, 0.52),
exon2 = c(0.61, 0.63, 0.59),
intron = c(0.41, 0.38, 0.44)
)
# Calcular GC medio de cada región
sapply(secuencias, mean)
# exon1 exon2 intron
# 0.547 0.610 0.410
# Test de normalidad en cada región
tests_norm <- lapply(secuencias, shapiro.test)
sapply(tests_norm, function(x) x$p.value)
$, [ ],
[[ ]]Esta distinción es uno de los puntos de mayor confusión al aprender R. La regla es simple pero su consecuencia es importante:
| Operador | Devuelve | Usar cuando… |
|---|---|---|
$ |
Elemento simplificado | Acceso interactivo por nombre fijo |
[ ] |
Mismo tipo de contenedor | Querés mantener estructura (sub-data.frame, sublista) |
[[ ]] |
El elemento en sí | Extraer un único elemento de lista o data.frame |
# Ejemplos con datos bioinformáticos
blast_df <- data.frame(
query = c("seq_001","seq_002","seq_003"),
subject = c("BRCA1","TP53","EGFR"),
pident = c(98.2, 87.6, 99.1),
evalue = c(2.4e-87, 8.1e-45, 1.2e-92)
)
resultados <- list(
blast = blast_df,
n_hits = 3L,
programa = "BLAST+ 2.14"
)
# ─── Diferencia crucial: [ ] vs [[ ]] ──────────────────────────────────────
blast_df["pident"] # data.frame de 1 columna — class: "data.frame"
blast_df[["pident"]] # el vector numérico — class: "numeric"
blast_df$pident # idéntico a [[]] para data.frame
resultados["blast"] # lista de 1 elemento — class: "list"
resultados[["blast"]] # el data.frame en sí — class: "data.frame"
# ─── Acceso con variable ────────────────────────────────────────────────────
columna <- "evalue"
blast_df[[columna]] # ✓ funciona
# blast_df$columna # ✗ busca columna literalmente llamada "columna"
# ─── Subsetting de data.frame ───────────────────────────────────────────────
blast_df[blast_df$evalue < 1e-50, ] # filas con e-value bajo
blast_df[blast_df$pident > 90, "subject"] # subjects con alta identidad
blast_df[, c("query","subject","evalue")] # columnas seleccionadas
@# S4 usa @ para slots — pero las funciones de acceso son preferibles
library(Biostrings)
# DNAStringSet — colección de secuencias DNA
seqs <- DNAStringSet(c(
BRCA1 = "ATGCGATCGATCGGCTAA",
TP53 = "ATGGAGGAGCCGCAGTCA",
EGFR = "ATGCGACCCTCCGGGACG"
))
class(seqs) # "DNAStringSet" — S4
length(seqs) # 3
names(seqs) # "BRCA1" "TP53" "EGFR"
seqs[["BRCA1"]] # la secuencia de BRCA1
width(seqs) # longitudes: 18 18 18
# GRanges — coordenadas genómicas
library(GenomicRanges)
gr <- GRanges(
seqnames = c("chr17","chr17","chr7"),
ranges = IRanges(start = c(43044295L, 7668402L, 55019017L),
end = c(43125483L, 7687550L, 55211628L)),
strand = c("-","-","+"),
gene = c("BRCA1","TP53","EGFR")
)
# Funciones de acceso (preferir sobre @)
seqnames(gr) # cromosomas
start(gr) # posiciones de inicio
end(gr) # posiciones de fin
strand(gr) # hebra
mcols(gr)$gene # metadatos (el factor "gene")
width(gr) # longitudes: 81189 19149 192612
### 2.8 Clases S3 y S4: El Sistema de Objetos de Bioconductor
Comprender S3 y S4 es esencial para trabajar con Bioconductor: cada
vez que uses Biostrings, GenomicRanges,
VariantAnnotation, o cualquier paquete de análisis, estarás
interactuando con objetos de estas clases.
# S3: lista con atributo "class"
# Ejemplo: resultado de alineamiento (clase inventada para ilustrar)
modelo <- lm(gc_content ~ longitud_pb, data = anotacion)
class(modelo) # "lm"
is.list(modelo) # TRUE ← internamente es una lista
# Acceso con $ (como cualquier lista)
modelo$coefficients
modelo$residuals
modelo$fitted.values
# Los métodos genéricos se adaptan según la clase del objeto
print(modelo) # salida formateada para "lm"
summary(modelo) # resumen estadístico para "lm"
plot(modelo) # gráficos de diagnóstico para "lm"
# ape (filogenética) usa S3
library(ape)
arbol <- nj(distancias) # Neighbor-Joining a partir de matriz de distancias
class(arbol) # "phylo"
is.list(arbol) # TRUE
arbol$tip.label # nombres de las hojas del árbol
arbol$edge # matriz de conexiones
plot(arbol) # dibuja el árbol
# S4: estructura validada con slots tipados
library(Biostrings)
# DNAStringSet
seqs <- DNAStringSet(c(BRCA1="ATGCGATCG", TP53="ATGGAGGAG"))
class(seqs) # "DNAStringSet"
isVirtualClass("DNAStringSet") # FALSE
is(seqs, "XStringSet") # TRUE — herencia de clases
slotNames(seqs) # ver slots disponibles
# Funciones de acceso (más robustas que @)
length(seqs) # número de secuencias
names(seqs) # nombres
width(seqs) # longitudes
as.character(seqs) # convertir a character R
# Operaciones nativas de Biostrings sobre secuencias
reverseComplement(seqs) # complemento reverso
letterFrequency(seqs, letters="GC") # contenido GC
subseq(seqs, start=1, end=3) # primeros 3 nucleótidos
# GRanges (GenomicRanges)
library(GenomicRanges)
is(gr, "GRanges") # TRUE
is(gr, "GenomicRanges") # TRUE — herencia
# Operaciones sobre coordenadas genómicas
flank(gr, width=500) # 500 pb upstream
resize(gr, width=1) # reducir a 1 pb (TSS, por ejemplo)
findOverlaps(gr, gr) # solapamientos entre rangos
# Ejemplo de herencia — cada nivel agrega funcionalidad
Vector
└── List
└── XStringSet
└── DNAStringSet ← secuencias DNA
RangedSummarizedExperiment
└── SummarizedExperiment ← datos genómicos + metadatos
└── DESeqDataSet ← análisis diferencial
GenomicRanges
└── GRanges ← coordenadas genómicas
└── GRangesList ← listas de coordenadas (ej: exones por gen)
### 2.9 Resumen: Cheat Sheet de Estructuras
| Estructura | Dim | Tipo | Crear | Acceder | Uso en bioinformática |
|---|---|---|---|---|---|
vector |
1D | Homogéneo | c(...) |
v[i], v["name"] |
IDs de genes, e-values, coordenadas, GC content |
matrix |
2D | Homogéneo | matrix(data,nr,nc) |
m[r,c] |
Distancias evolutivas, frecuencias alélicas, scores de alineamiento |
data.frame |
2D | Heterogéneo | data.frame(...) |
df$col, df[r,c] |
Tablas de anotación, resultados BLAST, metadatos, variantes |
list |
nD | Heterogéneo | list(a=1,b="x") |
l[["a"]], l$a |
Resultados de tests estadísticos, objetos S3 (phylo,
lm) |
S4 object |
Variable | Tipado/validado | Constructor del paquete | Funciones de acceso, @ |
DNAStringSet, GRanges,
SummarizedExperiment |
Guía elaborada para Bioinformática — Licenciatura en
Genética
IUCBC – CIMETSA · Córdoba, Argentina · 2026
Dr. Danilo G. Ceschin