-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy path9-1_Apply_Functions.R
308 lines (209 loc) · 8.68 KB
/
9-1_Apply_Functions.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
################################################################################
### R BASICS WORKSHOP ###
### PRESENTATION 9-1: Las funciones apply de R ###
### ###
### Unida de Servicios Bioinformáticos ###
### Instituto Nacional de Medicina Genómica ###
### Website: github.com/hachepunto/R_Basics_workshop ###
################################################################################
# La familia de funciones *apply* es usada para aplicar una función a cada
# elemento de una estructura de datos. En particular, es usada para aplicar
# funciones en matrices, data frames, arrays y listas.
# Con esta familia de funciones podemos automatizar tareas complejas usando
# poca líneas de código y es una de las características distintivas de R como
# lenguaje de programación.
# Las funciones de la familia apply son:
# • apply
# • lapply
# • sapply
# • tapply
# • vapply
# • eapply
# • mapply
# • rapply
# Aquí solo veremos las primeras cuatro por ser las básicas.
######################## apply ########################
# La funcion apply ejecuta la funcion "FUN", sobre todos las columnas
# (MARGIN =2) o renglones (MARGIN = 1) de una matriz.
# Uso:
#
# apply(X, MARGIN, FUN, ...)
#
# Argumentos:
# -X: una matriz o cualquier otro objeto que sea posible convertir en una matriz
# -MARGIN: Define sobre qué se va ejecutar la función y toma valores entre 1 y 2:
# -MARGIN=1`: La manipulación se hace por renglón.
# -MARGIN=2`: La manipulación se hace por columnas.
# -MARGIN=c(1,2)`: La manipulación se hace por renglones y columnas.
# -FUN: Indica que función se aplicará. Se puede usar funciones integradas como
# mean, median, sum, min, max e incluso funciones definidas por el usuario.
### Ejemplo sencillo
# Creamos una matriz de cuatro renglones
matriz <- matrix(1:16, nrow = 4)
# Aplicamos *apply*, dando la función *sum* el argumento FUN. Nota que solo
# necesitamos el nombre de la función, sin paréntesis. Por último, damos el
# argumento MARGIN = 1, para aplicar la función por renglón.
apply(X = matriz, MARGIN = 1, FUN = sum)
# Esto es equivalente a hacer lo siguiente:
sum(matriz[1, ])
sum(matriz[2, ])
sum(matriz[3, ])
sum(matriz[4, ])
# Si cambiamos el argumento MARGIN de MARGIN = 1 a MARGIN = 2, entonces la
# función se aplicará por columna.
apply(X = matriz, MARGIN = 2, FUN = sum)
### Ejemplo datos genómicos
### PREPARACIÓN DE DATOS: Comencemos por cargar unos datos de expresión de
# ENSEMBLE de Drosophila Los renglones son genes y hay información de cuatro
# tiempos (2, 6, 8 y 10 hrs) y otros metadatos.
data <- read.table("Datasets/rpkm_clase.tab", header = TRUE, sep="\t")
head(data)
# Filtramos los datos para quedarnos solo con los genes que tienen un RPKM mayor
# a 10 y luego generamos una matriz con los datos de expresión únicamente.
expressed <- subset(data, (rpkm2 > 10 & rpkm6 > 10 & rpkm8 > 10 & rpkm10 > 10))
#expressed$chr <- as.character(expressed$chr)
head(expressed)
rpkm <- cbind(expressed$rpkm2, expressed$rpkm6, expressed$rpkm8, expressed$rpkm10)
head(rpkm)
is.matrix(rpkm)
# Para obtener la media de la expresion para cada gene, a traves de los cuatro
# tiempos:
apply(rpkm, 1, mean) ##per row
# para obtener la media de la expresion para cada tiempo, sumando la expresion
# de todos los genes:
apply(rpkm, 2, mean) ##per column
# podemos utilizar estos resultados para hacer una grafica, o visualizar los
# datos de alguna manera
hist( apply(rpkm, 1, mean),
xlab = "Nivel de expresion",
ylab = "Numero de genes",
main = "Distribucion de la expresion promedio",
breaks=seq(min(apply(rpkm, 1, mean)),
max(apply(rpkm, 1, mean)),
length.out = 50)
)
######################## lapply ########################
# La "l" de *lapply* se refiere a "lista". La diferencia entre *lapply* y
# *apply* es el tipo de salida que genera cada una de ellas. La salida de
# *lapply* es una lista. *lapply* se puede usar sobre otros tipos de objetos
# como data frames y listas.
# La función *lapply* no necesita el parámetro "MARGIN".
# Uso:
#
# lapply(X, FUN, ...)
#
# Argumentos:
# -X: Un vector o un objeto (Lista o Data frame)
# -FUN: Función que se va a aplicar a cada elemento de X
### Ejemplo sencillo 1:
movies <- c("SPACE_ODYSSEY","BATMAN","VERTIGO","BRAZIL")
movies_lower <-lapply(movies, tolower)
str(movies_lower)
# Podemos usar *unlist* para convertir la lista en un vector.
movies_lower <-unlist(lapply(movies,tolower))
str(movies_lower)
# Ejemplo sencillo 2:
trees[1:5, ]
class(trees)
arboles <- lapply(X = trees, FUN = mean)
arboles
class(arboles)
### Caso con matriz
matriz <- matrix(1:9, ncol = 3)
lapply(matriz, quantile, probs = 0.8)
dataFrame <- as.data.frame(matriz)
lapply(dataFrame, quantile, probs = .8)
length(dataFrame)
dataFrame[1]
length(matriz)
matriz[1]
### Ejemplo con datos genómicos
rpkm.df <- as.data.frame(rpkm)
names(rpkm.df) <- c("t2", "t6", "t8", "t10")
head(rpkm.df)
# Podemos usar una función definida por nosotros dentro de las funciones *apply*.
# Quiero agregarle 5 al valor de expresion de todos los genes del tiempo 2
head(rpkm.df$t2)
lapply(head(rpkm.df$t2), function(x){x+5} )
######################## sapply ########################
# La función *sapply* hace lo mismo que *lapply* pero regresa un vector en lugar
# de una lista. "s" es de simplificar.
# Uso:
#
# sapply(X, FUN, ...)
#
# Arguments:
# -X: un vector o un objeto
# -FUN: Función que se va a aplicar a cada elemento de X
# Ejemplo sencillo:
dt <- cars
lmn_cars <- lapply(dt, min)
smn_cars <- sapply(dt, min)
lmn_cars
smn_cars
# Creamos una función llamada *avg* que calcule el promedio de entre el máximo
# y el mínimo de un vector:
avg <- function(x) {
(min(x) + max(x)) / 2
}
fcars <- sapply(dt, avg)
fcars
### Ejemplo con datos genómicos 1:
# Quiero eliminar el prefijo "FB" del id de flybase para cada uno de los genes.
lapply(data$flybase_id, function(x){ sub("FB", "", x) })
sapply(data$flybase_id, function(x){ sub("FB", "", x) })
sapply(data$flybase_id, function(x){ sub("FB", "", x) }, simplify = FALSE)
### Ejemplo con datos genómicos 2:
# Queremos obtener la expresion promedio de los genes por cromosoma para cada
# uno de los tiempos.
head(data)
# Necesitamos:
# 1. Obtener todos los genes de un cromosoma especifico.
# 2. Obtener el promedio de la expresion para esos genes en el tiempo 1 (2 hrs)
# 3. Obtener el promedio de la expresion para esos genes en el tiempo 2 (6 hrs)
# 4. Obtener el promedio de la expresion para esos genes en el tiempo 3 (8 hrs)
# 5. Obtener el promedio de la expresion para esos genes en el tiempo 4 (10 hrs)
# Repetir de 1 a 5 para todos los cromosomas.
# Primero vamos a generar una funcion que obtenga el promedio de expresión por
# cromosoma.
cromosoma <- "chr4"
genes.cromosoma <- subset(data, chr == cromosoma)
tiempos <- as.matrix(cbind(genes.cromosoma$rpkm2, genes.cromosoma$rpkm6, genes.cromosoma$rpkm8, genes.cromosoma$rpkm10))
dim(tiempos)
head(tiempos)
# Para obtener la exprsion promedio por columna.
mean.expr <- apply(X = tiempos, MARGIN = 2, FUN = mean)
mean.expr
# Creemos una funcion con las instrucciones que acabamos de escribir
gene_mean_expr <- function(x, data){
genes.cromosoma <- subset(data, chr == x)
tiempos <- as.matrix(cbind(genes.cromosoma$rpkm2, genes.cromosoma$rpkm6, genes.cromosoma$rpkm8, genes.cromosoma$rpkm10))
mean.expr <- apply(X = tiempos, MARGIN = 2, FUN = mean)
return(mean.expr)
}
gene_mean_expr("chr4", data)
# Hagamoslo para todos los cromosomas utilizando un apply
cromosomas <- as.character(unique(data$chr))
lapply(cromosomas, gene_mean_expr, data = data)
sapply(cromosomas, gene_mean_expr, data = data)
class(sapply(cromosomas, gene_mean_expr, data = data))
######################## tapply ########################
# La función *tapply* calcula una medida (mean, median, min, max, etc.) o
# alguna función para cada factor en un vector.
# Uso:
#
# tapply(X, INDEX, FUN = NULL, ...)
#
# Argumentos:
# -X: Un objeto, usualmente un vector.
# -INDEX: Una lista de uno o más factores del mismo tamaño que X.
# -FUN: Función que se va aplicar a cada elemento de X por cada factor de INDEX
data(iris)
class(iris$Sepal.Width)
class(iris$Species)
tapply(X = iris$Sepal.Width, INDEX = iris$Species, FUN = median)
## Ejemplo con datos genómicos
tapply(expressed$flybase_id, expressed$chr, length)
tapply(expressed$rpkm2, expressed$chr, mean)
tapply(expressed$flybase_id, list(expressed$chr, expressed$strand), length)
tapply(expressed$rpkm2, list(expressed$chr, expressed$strand), mean)