-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathBásicos.rmd
438 lines (289 loc) · 21.2 KB
/
Básicos.rmd
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
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
---
title: "Básicos"
---
<style>
body {
text-align: justify}
</style>
```{r setup, include=FALSE}
library(lubridate)
fecha <- today(tzone = "America/Lima")
mes <- month(fecha, label = T, abbr = F,
#locale = "es_PE.utf8"
)
```
**ULTIMA ACTUALIZACIÓN:**
La última actualización de este artículo se realizó el `r day(fecha)` de `r mes` del `r year(fecha)`.
# Tabla de Contenidos
- [Básicos](#T1)
- [Vectores](#T2)
# Básicos {#T1}
R es un entorno y lenguaje de programación con un enfoque al análisis estadístico[^1]. En palabras sencillas, R es un idioma con el que podemos pedirle a nuestra computadora que haga ciertas cosas para nosotros. En estos tutoriales usaremos R a través de RStudio[^2].
Debido a que casi todo lo que puedes hacer con R se hace a través de objetos, empezaremos presentando dos de los más comunes: los operadores y las funciones. Iremos conociendo otros tipos de objetos a medida que avancemos en los tutoriales.
## Operadores
Los operadores, como dice su nombre, nos permiten realizar operaciones entre ciertos valores de manera similar a como lo haríamos con una calculadora. Los siguientes nos permiten realizar operaciones aritméticas básicas:
|Operador|Operación|
|:------:|---------|
| `+` | Adición |
| `-` | Sustracción|
| `*` | Multiplicación|
| `/` | División real |
| `**` o `^`| Potencia |
| `()` | Para priorizar operaciones al interior de los paréntesis |
Podemos ver cómo lucen los operadores en funcionamiento al usarlos en R.
```{r}
(((1+2)*3)**2)/3
```
R primero opera el `1+2` al ser el nivel más profundo, obteniendo como resultado 3. Inmediatamente después, R realiza la operación `3*3` y obtiene 9. Después de esto, R opera el `9**2`obteniedo 81, y finaliza con la operación `81/3`, obteniedo 27 como resultado. Hasta este punto, R está siendo utilizado como una simple calculadora, pero podemos exigirle mucho más.
Pero antes de pasar a ello es importante conocer a otro operador fundamental, el de asignamiento. Está compuesto por el signo "menor que" (`<`) y el signo de resta (`-`), que al juntarse lucen como una flecha que apunta hacia la izquierda (`<-`). Este operador sirve para asignar un nombre a cualquier objeto o valor, de tal modo podamos acceder a él con mayor facilidad. Por ejemplo, podemos asignarle el nombre "result" al resultado de la operación que realizamos anteriormente.
```{r}
result <- (((1+2)*3)**2)/3
```
A simple vista, nada ha cambiado[^3], pero cuando accedemos al objeto `result` ahora obtenemos inmediatamente la respuesta de nuestra operación.
```{r}
result
```
Si por algún motivo necesitamos actualizar el valor asignado a nuestro objeto, basta con volver a asignar el mismo nombre a otro valor. Incluso se puede hacer referencia al valor anterior para modificarlo. No hay un límite de veces que el valor de un objeto puede ser modificado. En el siguiente ejemplo, sumaremos 3 a `result` para obtener 30.
```{r}
result <- result + 3
result
```
Hemos visto que podemos usar el operador `**` para elevar un número a cualquier potencia, pero no tenemos un operador para obtener la raíz. Podemos solucionar esto haciendo uso de funciones.
## Funciones
Las funciones nos permiten aplicar transformaciones a los valores u objetos que ingresemos en ellas. Para crear una función, debemos asignarle un nombre, argumentos y código que será utilizado para la transformación. Su forma general en R es la siguiente:
```{r, eval = FALSE}
nombredefuncion <- function(argumento_1, argumento_2, argumento_n){
código
}
```
Para que sea más entendible, haremos nuestra función para hallar la raíz cuadrada de cualquier número[^4] y la llamaremos `raiz_cuadrada`. Siempre es importante asignar un nombre significativo y que dé una buena idea del funcionamiento de la función.
```{r}
raiz_cuadrada <- function(x){
x**(1/2)
}
```
Como vemos en el cuerpo de la función, esta obtiene un número "x" y calcula su raíz cuadrada. Probemos su funcionamiento.
```{r}
raiz_cuadrada(25)
```
R ha calculado de manera correcta que la raíz cuadrada de 25 es 5. También podemos hacer una función para determinar la raíz cúbica de un número "x" de la misma manera.
```{r}
raiz_cubica <- function(x){
x**(1/3)
}
raiz_cubica(27)
```
Al probar su funcionamiento vemos que nos arroja el cálculo correcto. Podríamos hacer una función de raíz para cada número, pero como las funciones pueden tener más de un argumento, podemos usar eso para nuestra ventaja y hacer una función que aplique una raiz "n" a cualquier número "x".
```{r}
raiz_n <- function(x, n){
x**(1/n)
}
raiz_n(1024, 10)
```
Ese es el poder de las funciones, nos permiten hacer nuestras transformaciones de manera generalizada. Incluso podemos usar funciones en el cuerpo y argumento de otras funciones. En el siguiente ejemplo, usaremos la función predefinida `paste()`, que nos permite pegar textos para formar una oración.
```{r}
texto_raiz <- function(x, n){
paste("La raiz ", n, " de", x, "es ", raiz_n(x, n))
}
texto_raiz(1024, 10)
```
Los argumentos de una función no necesitan ir en la misma línea de código. Para una más fácil lectura, es posible separarlos por líneas (respetando las comas entre argumentos) siempre y cuando sigan dentro del mismo paréntesis de la función. Utilizaremos la función `paste()` para ejemplificar.
```{r}
paste("Un", "texto", "largo", "se", "imprime")
paste("Un",
"texto",
"largo",
"se",
"imprime")
```
Una vez que hemos entendido cómo usar funciones, estamos listos para conocer los paquetes.
## Usando paquetes
R es un lenguaje utilizado por muchas personas y cada quien escribe sus funciones según sus propias necesidades. Sin embargo, no resulta extraño que varios usuarios necesiten lo mismo. Por ejemplo, resulta lógico pensar que no somos las únicas personas que necesitan obtener la raíz "n" de un número.
Es en este punto que entran en juego los paquetes, una colección de funciones y datos que los usuarios de R comparten entre sí para facilitar el trabajo a los demás y evitar la repetición innecesaria de creación de funciones de uso común o de alta utilidad[^5]. Hay paquetes de todo tipo, desde los que te permiten realizar una función muy específica (como `clipr` que es usado para copiar y pegar información contenida en el portapapeles del sistema) hasta los que te permiten expandir los límites de lo que R es capaz de hacer (como `reticulate`, que te permite ejecutar código del lenguaje de programación Python en tu entorno R).
Cuando inicias **R** se activa un grupo base de paquetes. Estos han sido desarrollados por el R Core Team y son la pieza fundamental de su funcionalidad.
Puedes instalar paquetes usando la función `install.packages()` y poniendo como argumento el nombre del paquete entre comillas `""`. Este procedimiento sólo será necesario una vez, ya que después de instalados, los paquetes son conservados en la memoria de la computadora. Aquí puedes ver algunos ejemplos:
```{r, eval = FALSE}
install.packages("ggplot2")
install.packages("DT")
install.packages("RColorBrewer")
```
Pero tenerlos instalados no es suficiente. Cada vez que necesitas usar un paquete lo puedes llamar con `library(paquete)`. Esto hará que sus funciones y objetos estén disponibles para el uso. Te darás cuenta que no has llamado al paquete si corres un código y el resultado es un error como este:
```{r, error = TRUE}
glue("texto", "de", "ejemplo")
```
Esto significa que no has llamado al paquete necesario usando `library()`. En cambio, si al llamar al paquete te da como resultado un error de este tipo:
```{r, error = TRUE}
library(testpackage)
```
Significa que necesitas instalarlo. No hay que asustarse al obtener un mensaje de error alguna vez, por lo general suelen ser bastante explicativos respecto a por qué son causados y nos permiten corregir aquello en lo que nos equivocamos.
# Vectores {#T2}
Los siguientes objetos fundamentales para el manejo de R son los vectores. Estos pueden ser de dos tipos: atómicos y listas. La diferencia entre ellos radica en el tipo de información que pueden contener. Para efectos de estos tutoriales, consideraremos las listas como vectores "especiales" junto a otros que explicaremos más adelante.
## Vectores atómicos
Los cuatro principales tipos de vectores atómicos son: *logical*, *double*, *integer* y *character*[^6]. Los vectores de tipo *logical* pueden asumir dos valores: `TRUE` o `FALSE`(o en su forma abreviada `T` o `F`). Los de tipo *double* e *integer* asumen valores numéricos, los *double* pueden asumir valores racionales y los *integer* sólo valores enteros. Los vectores de tipo *character* asumen cualquier cadena de texto. En el siguiente recuadro de código podemos ver un ejemplo de cada uno:
```{r}
v_logical <- TRUE
v_double <- 3.1416
v_integer <- 5L
v_character <- "Hola mundo"
```
Si estamos atentos, vemos que el *integer* va acompañado de una "L" al final. Esto es necesario porque R interpreta por defecto cualquier número como *double*. Tanto los *double* como los *integer* pertenecen a la categoría de vectores numéricos. Los *character* siempre estarán rodeados de comillas (`""`). Para comprobar si nuestro vector es de un tipo determinado utilizamos una función de forma `is.XXX()` reemplazando el "XXX" por el tipo que queremos comprobar.
```{r}
is.logical(v_logical)
is.numeric(v_double)
is.integer(v_double)
```
Podemos ver que por cada consulta obtenemos un valor *logical* `TRUE` cuando se cumple la condición y `FALSE` cuando no se cumple. Es decir, es cierto que `v_logical`es *logical*, es cierto que `v_double` es numérico y es falso que `v_double` es *integer*. El valor *logical* obtenido con cada consulta es un vector en sí mismo.
Otra manera de verificar el tipo de vector que tenemos es con la función `typeof()`. Esta nos devuelve un *character* indicando el tipo de vector que tenemos.
```{r}
typeof(v_character)
typeof(v_integer)
```
### Vectores con más de un elemento y operador de secuencia simple
Hasta el momento hemos visto vectores que contienen un solo elemento. Sin embargo, es sumamente común encontrarse con vectores de mayor longitud. Por ejemplo, el vector `letters` contiene todas las letras minúsculas del alfabeto. Podemos consultar la longitud de un vector con la función `length()`. Esto es muy útil cuando sabemos que nuestro vector podría contener una gran cantidad de elementos y no queremos inspeccionarlos todos. El número que vemos rodeado entre corchetes (`[]`) en nuestro resultado nos indica el índice que el elemento siguiente tiene en el vector. Es por ello que hasta el momento en cada operación que realizábamos hemos obtenido un "[1]" antes de cada resultado.
```{r}
length(v_logical)
length(letters)
print(letters)
```
Para formar vectores de longitud mayor a uno se utiliza la función `c()` agregando como argumentos todos los elementos que queremos.
```{r}
mi_vector_largo <- c("elemento1",
"elemento2",
"elemento3",
"elemento4")
print(mi_vector_largo)
```
Para vectores numéricos, también es posible utilizar el signo dos puntos (`:`) como operador para crear una secuencia, que avanza de uno en uno, desde un número a otro. El vector resultado incluirá a los dos números utilizados en la operación.
```{r}
mi_vector_numerico1 <- 1:6
print(mi_vector_numerico1)
```
Podemos hacer uso de `c()` nuevamente para seguir haciendo crecer nuestro vector. Incluso podemos usar una operación de secuencia como argumento. Al consultar el tipo de vector que hemos creado, vemos que mantiene el mismo tipo que sus "ancestros": *integer*.
```{r}
mi_vector_numerico2 <- 11:16
mi_vector_muy_largo <- c(mi_vector_numerico1,
mi_vector_numerico2,
21:26)
print(mi_vector_muy_largo)
typeof(mi_vector_muy_largo)
```
### Coerción de vectores
Crear vectores más largos puede tener efectos inesperados para el usuario que no está atento. Veamos el siguiente ejemplo:
```{r}
vector_combinado <- c(mi_vector_muy_largo, "1")
typeof(vector_combinado)
```
Al agregar `"1"` a nuestro vector, su tipo ha cambiado a *character*. ¿Por qué sucede esto? En primer lugar, hay que tener claro que `"1"` no es lo mismo que `1`. Recordemos que todo valor que está entre comillas es de tipo *character*, incluso si se trata de números.
En segundo lugar, tengamos en cuenta que los vectores atómicos sólo pueden tener un tipo. Esto quiere decir que cuando los tipos de los elementos que se combinan dentro del vector son diferentes, R debe decidir cuál de los tipos de vector mantener, eligiéndo sólo uno. Este procedimiento es llamado **coerción**.
Aunque suena complicado, las reglas de coerción son bastante sencillas. R le dará prioridad a mantener el tipo de vector según el siguiente orden:
1. Character
2. Double
3. Integer
4. Logical
Es decir, ante cualquier conflicto en el tipo de vectores a combinar se preservará el tipo que tenga más alta prioridad. Si nos detenemos a analizar por qué sucede, es bastante evidente. Los valores *logical* son en realidad leídos por la computadora como `1` cuando son `TRUE` y como `0` cuando son `FALSE`. Es por ello que la siguiente operación no nos arroja un error.
```{r}
1L + TRUE
```
Del mismo modo, sabemos que cualquier número entero también puede ser expresado como número racional. Es por ello que los *integer* son coercionados a *double* cuando hay conflicto entre ellos.
```{r}
typeof(1L + 3.1416)
```
¿Es posible convertir texto a números en R? No[^7]. Es por ello que cuando un vector tipo *character* se combina con cualquier otro tipo de vector, prevalece el tipo *character*, como en el ejemplo que vimos al inicio de esta sección.
### Coerción explícita y valores NA
En todos los casos de coerción que hemos mencionado hasta el momento R ha decidido mediante sus propias reglas qué tipo de vector debe prevalecer, aplicando **coerción implícita**. Este procedimiento puede ocasionar problemas cuando el usuario no tiene suficientemente claras las reglas de coerción.
La **coerción explícita** permite decidir de antemano qué tipo de vector queremos obtener. Para ello se hace uso de una función de la forma `as.XXX()` donde `XXX` representa el tipo deseado.
```{r}
vector_true_integer <- as.integer(TRUE)
typeof(vector_true_integer)
```
En este ejemplo, hemos usado `as.integer()` para cambiar el tipo de nuestro vector, de *logical* a *integer*. Es posible hacer lo mismo para otros tipos de vectores. Tomemos en cuenta que la transformación se realiza de manera directa, sin respetar el orden de prioridad.
```{r}
as.character(TRUE)
```
Es por ello que `TRUE` se convierte directamente en el *character* `"TRUE"` sin convertirse primero en el *integer* `1L`, luego en el *double* `1` y luego en el *character* `"1"`. De aquí viene el verdadero poder de la coerción explícita, porque nos permite incluso "revertir" el orden de prioridad que R usa en la coerción implícita. Es decir, podemos convertir **cualquier** tipo de vector a otro.
```{r}
typeof(as.logical("TRUE"))
typeof(as.integer("10"))
typeof(as.integer(5.0))
typeof(as.double("6.108"))
```
De todos modos, esto se debe usar con precaución. Sabemos que todo *logical* puede convertirse a *integer*, estos a su vez pueden convertirse a *double* y estos a *character* sin perder ninguna información. No sucede lo mismo en el procedimiento reverso. Por ejemplo, esto sucede cuando queremos convertir un *double* con cifras decimales a *integer*.
```{r}
as.integer(5.4234)
```
El contenido decimal se pierde, porque R no lo necesita en el *integer*, y no es posible recuperarlo aún retransformando el valor a *double* en la misma línea de código.
```{r}
as.double(as.integer(5.4234))
```
Algo similar sucede cuando intentamos convertir a *logical* valores numéricos mayores a 1.
```{r}
as.logical(8)
as.logical(-0.000000135)
```
R interpreta como `TRUE` todo número diferente a `0`. Es probable que no sea el resultado que esperábamos en esta transformación. Pero todavía hay más. ¿Qué sucederá si intentamos convertir una **palabra** a número?
```{r}
as.integer("sustantivo")
```
R no es capaz de asignar un valor numérico a `"sustantivo"` y como resultado nos arroja un advertencia o *warning*: `NAs introduced by coercion`. El valor `NA` representa un valor perdido y no es posible transformarlo. Los valores perdidos pueden aparecer en nuestros datos por diferentes motivos, desde la recolección hasta la transformación de nuestra data. Debemos ser extremadamente cuidadosos al trabajar con ellos, porque pueden generar algunos problemas indeseados. Por ejemplo, si queremos obtener la suma de todos los elementos de un vector, usando la función `sum()`, y resulta que uno de ellos es un `NA`.
```{r}
vector_con_NA <- c(1, 2, 3, 4, NA, 6, 7)
sum(vector_con_NA)
```
El resultado obtenido es simplemente `NA`. El mismo problema se extiende al querer obtener un promedio usando la función `mean()`.
```{r}
mean(vector_con_NA)
```
Felizmente, estas funciones permiten proporcionar el argumento `na.rm = TRUE` para ignorar los valores `NA` y trabajar sólo con valores válidos.
```{r}
sum(vector_con_NA, na.rm = TRUE)
mean(vector_con_NA, na.rm = TRUE)
```
Sin embargo, no necesariamente encontraremos esta herramienta en todas las funciones que trabajan con vectores. Por ello es indispensable estar atentos al trabajar nuestros datos y revisar la documentación de las funciones con las que estamos trabajando.
## Vectores especiales
Hasta el momento hemos trabajado con vectores atómicos. Hemos comprendido que hay cuatro tipos de ellos, que podemos agregarles elementos y que pueden ser coercionados implícita y explícitamente a otros tipos.
Es posible crear vectores que tengan un comportamiento particular al asignarles atributos (`attributes`). Este es el caso de los factores y los datetimes.
La función `attributes()` nos permite consultar los atributos que contiene un objeto. Veamos qué sucede cuando consultamos por los atributos de los vectores que creamos antes.
```{r}
attributes(v_integer)
attributes(mi_vector_muy_largo)
```
Por defecto, los vectores atómicos no tienen ningún atributo, es por ello que en la consulta nos arroja el resultado `NULL`. Veremos que con los factores y datetimes no sucede lo mismo.
No es propósito de este tutorial enseñar a agregar o modificar los atributos de los vectores, sino de dar a conocer algunos de los más utilizados.
### Factores
Los *factor* son vectores con un conjunto predefinido de valores. Pueden ser formados a partir de otros vectores con la función `factor()`, cuyo primer argumento es el vector en cuestión.
```{r}
numeros <- c("uno", "dos", "dos", "uno", "uno")
factor_numeros <- factor(numeros)
print(factor_numeros)
```
Vemos que al ser impresos se parecen a un vector *character*. Sin embargo, al consultar por su tipo podemos ver qué son internamente.
```{r}
typeof(factor_numeros)
```
Consultemos sus `attributes()` para entender qué está sucediendo con este vector.
```{r}
attributes(factor_numeros)
```
Lo primero que debemos notar es el atributo `class`. Este será una característica común de los vectores especiales. La clase es la que determina el comportamiento que tendrán estos vectores.
El siguiente es el atributo `levels`, que nos indica qué valores pueden asumir los elementos que pertenecen a este vector. Este atributo se imprime automáticamente junto al vector. En el caso de `factor_numeros`, los `levels` fueron detectados automáticamente por R. Sin embargo, la función `factor()` nos permite indicar manualmente estos valores.
```{r}
factor_manual <- factor(numeros, levels = c("uno", "dos", "tres"))
print(factor_manual)
```
Vemos que ahora `"tres"` forma parte de los `levels` a pesar de que no existe en nuestro vector.
Además de ello, los *factor* son muy útiles como paso intermedio para cambiar de tipo nuestros *character*. Recordemos que al coercionar explícitamente un *character* a un valor numérico, R nos arrojaba como resultado un `NA`. Si transformamos primero nuestro *character* a un *factor*, esto sí es posible sin incurrir en un `NA`.
```{r}
as.integer(factor_manual)
```
Es por todo ello que los *factor* son bastante utilizados para tratar con datos categóricos.
### Datetimes
Soon...
### Listas
Soon...
[^1]: Definición obtenida de https://es.wikipedia.org/wiki/R_(lenguaje_de_programaci%C3%B3n)
[^2]: RStudio es un Entorno de desarrollo integrado (IDE) para R. Para instalar ambos, recomendamos seguir las instrucciones del punto 1.4.1 y 1.4.2 del siguiente enlace https://es.r4ds.hadley.nz/introducci%C3%B3n.html
[^3]: Si estamos usando RStudio podemos ver que en en la sección Values de la pestaña "Environment" ha aparecido nuestro objeto "result" asociado al resultado de la operación.
[^4]: Teniendo en cuenta que la raíz cuadrada de X puede ser expresada como potencia de X en la forma X^(1/2)^
[^5]: Podemos obtener la mayor parte de paquetes del CRAN (Comprehensive R Archive Network). La función `install.packages()` busca allí los paquetes que le pedimos que descargue.
[^6]: No se conoce una traducción oficial al castellano para los tipos de vectores. En la versión en español de "R for data science" son llamados lógicos, dobles, enteros y caracter.
[^7]: Al menos no de manera automática, como sí se puede en otros lenguajes de programación.