Capitulo 7 data.table
El package data.table
es un paquete que lleva la eficiencia al siguiente nivel. Como dije, la sintaxis es algo menos intuitiva que el lenguaje tidyverse
pero todo sea por la eficiencia :).
Los Data Table pueden ser utilizados como data.rame. Si se hace un class(...)
de un data.table se imprime una lista con dos valores: “data.table” “data.frame”, identificando que los objetos data.able
también pueden ser considerados como data.frame y las librerías que solo usan data.frame no tendrían problemas al usar data.table
.
7.1 Importar y exportar datos
El package data.table
tiene sus propias funciones para importar y exportar datos. Las funciones son fread()
y fwrite()
. Estas funciones sirven para cargar archivos tabulares, o de texto, separados por cierto separados. Aquí tenemos los argumentos más importantes de estas funciones:
x
: el objeto que queremos exportar. En caso de importar, esto no hace falta.file
: el lugar donde queremos guardar el archivo y su extensión.sep
: el delimitador entre columnas. En un archivo csv por lo general es “,”dec
: el separador decimal.dateTimeAs
: formato en el que guardar objetos de fecha. Por defecto es “ISO”.
Vamos a probar a cargar “Historicos”
data.link = "C:/Users/ip30/Dropbox/Terreno/cursos/Formadores IT/Curso intro R/Curso R base/datos/"
HS <- fread(paste0(data.link,"Historicos_siniestros.txt"),sep=";",dec=",")
str(HS)
## Classes 'data.table' and 'data.frame': 29096 obs. of 15 variables:
## $ CO_SINIESTRO : int 2361644 2361644 2361644 2361644 2361644 2361644 2361644 2361644 2361644 2361644 ...
## $ IN_ORDEN : int 1 2 3 4 5 6 7 8 9 10 ...
## $ FX_OPERACION : chr "04Jul2018" "01Aug2018" "02Aug2018" "10Aug2018" ...
## $ FX_DECLARACION_SINIESTRO : chr "04Jul2018" "01Aug2018" "01Aug2018" "01Aug2018" ...
## $ FX_ENTRADA_SINIESTRO : chr "04Jul2018" "01Aug2018" "01Aug2018" "01Aug2018" ...
## $ FX_ADMISION_SINIESTRO : chr "" "" "02Aug2018" "02Aug2018" ...
## $ CO_SITUACION_SINIESTRO : int 1 1 1 1 1 1 1 1 1 1 ...
## $ CO_MOTIVO_RECHAZO_SINIESTRO: int 0 0 0 0 0 0 0 0 0 0 ...
## $ CO_TIPO_ESTADO_SINIESTRO : int 9 4 5 5 5 1 1 3 3 3 ...
## $ IM_CREDITO_TOTAL : num 7000 7000 4200 4200 4200 4200 4200 4200 4200 4200 ...
## $ IM_CREDITO_PENDIENTE : num 7000 7000 4200 4200 4200 4200 4200 4200 4200 4200 ...
## $ IM_SUMA_ASEGURADA : num 0 0 3780 3780 3780 3780 3780 3780 3780 3780 ...
## $ IM_SUMA_GARANTIZADA : num 0 0 3213 3213 3213 ...
## $ IM_SINIESTRO_CREDITO : num 0 0 0 0 0 0 0 0 0 0 ...
## $ IM_SINIESTRO_CREDITO_ACU : num 0 0 0 0 0 0 0 0 0 0 ...
## - attr(*, ".internal.selfref")=<externalptr>
Como vemos, el formato data.table
es algo diferente a los tibble
de tidyverse, pero no os preocupeis, es muy parecido :)
Cargar fechas es una de las limitaciones actuales de read.table
, pero seguramente pronto renovarán la función para ello. Podemos usar la función que vimos anydate()
o anytime()
para poner bien las variables que nos interesan.
7.2 Sintaxis base
Esta es la base para manejarnos con una data.table
: DT[ i , j , by ]. Tiene tres partes que hemos llamado i
, j
y by
:
i
: corresponde a las líneas con las que queremos trabajar.j
: corresponde a las columnas y la usaremos para hacer cálculos y resúmenes, seleccionar variables y crear nuevas variables.by
: corresponde a las agrupaciones que queremos hacer.
7.2.1 La parte i
La parte i
se usa para filtrar las líneas con las que queremos trabajar. Por ejemplo:
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1: 4.9 3.0 1.4 0.2 setosa
## 2: 4.7 3.2 1.3 0.2 setosa
## 3: 4.6 3.1 1.5 0.2 setosa
## 4: 5.0 3.6 1.4 0.2 setosa
## 5: 5.4 3.9 1.7 0.4 setosa
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1: 4.9 3.0 1.4 0.2 setosa
## 2: 4.7 3.2 1.3 0.2 setosa
## 3: 4.6 3.1 1.5 0.2 setosa
## 4: 5.0 3.6 1.4 0.2 setosa
## 5: 5.4 3.9 1.7 0.4 setosa
O también podemos usar nombres de columnas y condiciones para hacer esto:
IRIS[Species %in% c("setosa","virginica")][1: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
Y podemos poner varias condiciones:
IRIS[Species == "setosa" | Species=="virginica" ][1:5]
## 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
## 5: 5.0 3.6 1.4 0.2 setosa
IRIS[Species %in% c("setosa","virginica") & Petal.Width < 1][1:3]
## 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
Fijaros, que he concatenado varios []
seguidos, y le hemos dado la forma IRIS[][]
. Esto es una concatenación de acciones, muy parecido a lo que haciamos con %>%
en tidyverse.
7.2.2 La parte j
La parte j
se usa para seleccionar columnas, crear nuevas variables y aplicar cosas o funciones sobre ellas ellas.
7.2.2.1 Operaciones y resumen de variales
Podemos sacar valores de interés
IRIS[1:20,mean(Petal.Length)]
## [1] 1.435
IRIS[,table(Species)]
## Species
## setosa versicolor virginica
## 50 50 50
En la primera línea hemos sacado la media de “Sepal.Length” para las 20 primeras observaciones. Y en la segunda línea hemos sacado cuantas observaciones tenemos para cada “Species” :)
Si queremos seleccionar varias columnas en la parte j
y queremos hacer cosas con ellas, debemos usar el verbo .()
. Es como si usásemos el verbo list()
Y podemos ponerle nombres para ser claros:
7.2.2.2 Seleccionar
Podemos seleccionar variables.
7.2.2.3 Crear
Mediante :=
también podemos crear nuevas columnas:
IRIS[, sepal_area := Sepal.Length*Sepal.Width][1:3]
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species sepal_area
## 1: 5.1 3.5 1.4 0.2 setosa 17.85
## 2: 4.9 3.0 1.4 0.2 setosa 14.70
## 3: 4.7 3.2 1.3 0.2 setosa 15.04
Y si queremos hacer esto con varias variables:
IRIS[, `:=`(sepal_area = Sepal.Length*Sepal.Width,
petal_area = Petal.Length*Petal.Width)][1:3]
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species sepal_area
## 1: 5.1 3.5 1.4 0.2 setosa 17.85
## 2: 4.9 3.0 1.4 0.2 setosa 14.70
## 3: 4.7 3.2 1.3 0.2 setosa 15.04
## petal_area
## 1: 0.28
## 2: 0.28
## 3: 0.26
# o
IRIS[, c("sepal_area", "petal_area") := .(Sepal.Length*Sepal.Width, Petal.Length*Petal.Width)][1:3]
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species sepal_area
## 1: 5.1 3.5 1.4 0.2 setosa 17.85
## 2: 4.9 3.0 1.4 0.2 setosa 14.70
## 3: 4.7 3.2 1.3 0.2 setosa 15.04
## petal_area
## 1: 0.28
## 2: 0.28
## 3: 0.26
y si queremos crear variables de forma secuencial:
IRIS[, c("sepal_area", "cuadrado_sepal_area") := .(a <- Sepal.Length*Sepal.Width, a^2)][1:3]
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species sepal_area
## 1: 5.1 3.5 1.4 0.2 setosa 17.85
## 2: 4.9 3.0 1.4 0.2 setosa 14.70
## 3: 4.7 3.2 1.3 0.2 setosa 15.04
## petal_area cuadrado_sepal_area
## 1: 0.28 318.6225
## 2: 0.28 216.0900
## 3: 0.26 226.2016
7.2.3 La parte by
Como podemos imaginar, se hacen las agrupaciones que puedan interesarnos para sacar operaciones sobre la parte j
. Por ejemplo:
IRIS[,.(media_PL = mean(Petal.Length)),by=Species]
## Species media_PL
## 1: setosa 1.462
## 2: versicolor 4.260
## 3: virginica 5.552
IRIS[,.(media_PL = mean(Petal.Length)), Species]
## Species media_PL
## 1: setosa 1.462
## 2: versicolor 4.260
## 3: virginica 5.552
Sacamos la media de “Petal.Length” por “Species”. Igual que antes, si queremos agrupar por varias variables, usaremos .()
:
IRIS[,col := rep(c("A","B"),length.out=nrow(IRIS))] ## hemos creado una nueva variables en IRIS
IRIS[1:7]
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species sepal_area
## 1: 5.1 3.5 1.4 0.2 setosa 17.85
## 2: 4.9 3.0 1.4 0.2 setosa 14.70
## 3: 4.7 3.2 1.3 0.2 setosa 15.04
## 4: 4.6 3.1 1.5 0.2 setosa 14.26
## 5: 5.0 3.6 1.4 0.2 setosa 18.00
## 6: 5.4 3.9 1.7 0.4 setosa 21.06
## 7: 4.6 3.4 1.4 0.3 setosa 15.64
## petal_area cuadrado_sepal_area col
## 1: 0.28 318.6225 A
## 2: 0.28 216.0900 B
## 3: 0.26 226.2016 A
## 4: 0.30 203.3476 B
## 5: 0.28 324.0000 A
## 6: 0.68 443.5236 B
## 7: 0.42 244.6096 A
IRIS[,.(media_PL = mean(Petal.Length)),by=.(Species,col)]
## Species col media_PL
## 1: setosa A 1.456
## 2: setosa B 1.468
## 3: versicolor A 4.308
## 4: versicolor B 4.212
## 5: virginica A 5.564
## 6: virginica B 5.540
7.2.4 Algunas otras funciones interesantes:
7.2.4.1 .N
.N
en i
nos da la última fila. En j
el número de filas en un grupo.
7.2.4.2 .I
.I
en j
nos da un vector con los números de fila de los dato en la table (filtrados por i
).
(a <- IRIS[,.I[Species=="virginica"]])
## [1] 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
## [20] 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
## [39] 139 140 141 142 143 144 145 146 147 148 149 150
IRIS[a[1:3]]
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species sepal_area
## 1: 6.3 3.3 6.0 2.5 virginica 20.79
## 2: 5.8 2.7 5.1 1.9 virginica 15.66
## 3: 7.1 3.0 5.9 2.1 virginica 21.30
## petal_area cuadrado_sepal_area col
## 1: 15.00 432.2241 A
## 2: 9.69 245.2356 B
## 3: 12.39 453.6900 A
7.2.4.3 .SD
.SD
en j
nos trabaja sobre el subgrupo de datos seleccionados en by
.
IRIS[,index := 1:nrow(IRIS)] # crear variable index
IRIS[,.SD[1],Species] ## primera fila de cada grupoIRIS
## Species Sepal.Length Sepal.Width Petal.Length Petal.Width sepal_area
## 1: setosa 5.1 3.5 1.4 0.2 17.85
## 2: versicolor 7.0 3.2 4.7 1.4 22.40
## 3: virginica 6.3 3.3 6.0 2.5 20.79
## petal_area cuadrado_sepal_area col index
## 1: 0.28 318.6225 A 1
## 2: 6.58 501.7600 A 51
## 3: 15.00 432.2241 A 101
IRIS[,.SD[.N],Species] ## última fila de cada grupo
## Species Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1: setosa 5.0 3.3 1.4 0.2
## 2: versicolor 5.7 2.8 4.1 1.3
## 3: virginica 5.9 3.0 5.1 1.8
IRIS[,.SD[c(1,.N)],Species] ## primera y última fila de cada grupo
## Species Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1: setosa 5.1 3.5 1.4 0.2
## 2: setosa 5.0 3.3 1.4 0.2
## 3: versicolor 7.0 3.2 4.7 1.4
## 4: versicolor 5.7 2.8 4.1 1.3
## 5: virginica 6.3 3.3 6.0 2.5
## 6: virginica 5.9 3.0 5.1 1.8
Y dentro de SD podemos hacer aplicar funciones usando la función vectorizada lapply()
:
.SDcols
especifica las columnas de la data.table que se incluyen en .SD
. Por lo tanto, si queremos sacar la media de las variables “Sepal.Width”, “Sepal.Length” y “Petal.Length” por especies, podemos elegir trabajar sólo con esas columnas usando .SDcols
:
7.2.4.4 .GRP
.GRP
en j
nos da la indexación de los grupos que tenemos.
IRIS[ , i := .GRP, by = Species]
IRIS
Sepal.Length Sepal.Width Petal.Length Petal.Width Species i col
## 1: 5.1 3.5 1.4 0.2 setosa 1 A
## 2: 4.9 3.0 1.4 0.2 setosa 1 B
## 3: 4.7 3.2 1.3 0.2 setosa 1 A
## 4: 4.6 3.1 1.5 0.2 setosa 1 B
## 5: 5.0 3.6 1.4 0.2 setosa 1 A
## ---
## 146: 6.7 3.0 5.2 2.3 virginica 3 B
## 147: 6.3 2.5 5.0 1.9 virginica 3 A
## 148: 6.5 3.0 5.2 2.0 virginica 3 B
## 149: 6.2 3.4 5.4 2.3 virginica 3 A
## 150: 5.9 3.0 5.1 1.8 virginica 3 B
# o
IRIS[ , i := .GRP, by = .(Species,col)]
IRIS
Sepal.Length Sepal.Width Petal.Length Petal.Width Species i col
## 1: 5.1 3.5 1.4 0.2 setosa 1 A
## 2: 4.9 3.0 1.4 0.2 setosa 2 B
## 3: 4.7 3.2 1.3 0.2 setosa 1 A
## 4: 4.6 3.1 1.5 0.2 setosa 2 B
## 5: 5.0 3.6 1.4 0.2 setosa 1 A
## ---
## 146: 6.7 3.0 5.2 2.3 virginica 6 B
## 147: 6.3 2.5 5.0 1.9 virginica 5 A
## 148: 6.5 3.0 5.2 2.0 virginica 6 B
## 149: 6.2 3.4 5.4 2.3 virginica 5 A
## 150: 5.9 3.0 5.1 1.8 virginica 6 B
7.2.5 Algunos ejercicios
7.2.5.1 Base de datos de juguete
Volvemos al paquete nycflights13
y la base de datos data.frame flights
.
Utiliza data.table()
para responder a las siguientes preguntas:
- ¿Cuantos vuelos se realizan en total cada mes?
- ¿Qué aeropuerto acumula el mayor número de salidas de vuelos en todo el año?
- ¿Qué compañía acumula el mayor número de salida de vuelos en los meses de verano (jun-sep.)?
Lo primero que debemos hacer es convertir la tabla a formato data.table()
, i.e.:
7.2.5.2 Nuestra base de datos
Cargar los datos “Siniestros” e “HistoricosSiniestros”, y poner todas las variables como queremos.
Para poner bien las fechas, recordad como se nombran variables en R y el paquete
anytime
. Si teneis una base de datos enorme, la funciónanytime()
puedee ser un poco lenta. El paquetefasttime
es el más eficiente, pero puede ser complicado de usar dependiendo el formato de fecha/hora que tengamos.Crear la variable “Mes_FX_FACTURA”. Recordad el paquete
lubridate
.En “HistoricosSiniestros” sacar el último registro de todos los CO_registro
Agrupar las sumas garantizadas por més de declaración
Agrupar las sumas garantizadas por día de declaración a partir del 5 de agosto
Ordenar por día el resultado
Hacedme una gráfica para ver la suma garantizada
7.3 Concatenar
Como ya hemos visto, en data.table
podemos concatenar acciones con diferentes [] seguidos:
(DT <- data.table(V1=c(1L,2L), V2=LETTERS[1:3], V3=round(rnorm(4),4),V4=1:12))
## V1 V2 V3 V4
## 1: 1 A 1.0963 1
## 2: 2 B -0.9033 2
## 3: 1 C -1.1891 3
## 4: 2 A 1.0650 4
## 5: 1 B 1.0963 5
## 6: 2 C -0.9033 6
## 7: 1 A -1.1891 7
## 8: 2 B 1.0650 8
## 9: 1 C 1.0963 9
## 10: 2 A -0.9033 10
## 11: 1 B -1.1891 11
## 12: 2 C 1.0650 12
DT[,V4.cumsum:=cumsum(V4)]
DT
## V1 V2 V3 V4 V4.cumsum
## 1: 1 A 1.0963 1 1
## 2: 2 B -0.9033 2 3
## 3: 1 C -1.1891 3 6
## 4: 2 A 1.0650 4 10
## 5: 1 B 1.0963 5 15
## 6: 2 C -0.9033 6 21
## 7: 1 A -1.1891 7 28
## 8: 2 B 1.0650 8 36
## 9: 1 C 1.0963 9 45
## 10: 2 A -0.9033 10 55
## 11: 1 B -1.1891 11 66
## 12: 2 C 1.0650 12 78
DT[,V4.cumsum:=cumsum(V4)] [order(-V3)]
## V1 V2 V3 V4 V4.cumsum
## 1: 1 A 1.0963 1 1
## 2: 1 B 1.0963 5 15
## 3: 1 C 1.0963 9 45
## 4: 2 A 1.0650 4 10
## 5: 2 B 1.0650 8 36
## 6: 2 C 1.0650 12 78
## 7: 2 B -0.9033 2 3
## 8: 2 C -0.9033 6 21
## 9: 2 A -0.9033 10 55
## 10: 1 C -1.1891 3 6
## 11: 1 A -1.1891 7 28
## 12: 1 B -1.1891 11 66
DT[,V4.cumsum:=cumsum(V4)] [order(-V3)] [V4<6]
## V1 V2 V3 V4 V4.cumsum
## 1: 1 A 1.0963 1 1
## 2: 1 B 1.0963 5 15
## 3: 2 A 1.0650 4 10
## 4: 2 B -0.9033 2 3
## 5: 1 C -1.1891 3 6
7.4 JOINS
Se puede usar sintaxis data.table
(DT) o la función merge()
Tipos:
- INNER: en DT =
X[Y, nomatch=0]
. Enmerge()
= merge(X, Y, all=FALSE) - LEFT OUTER: en DT =
Y[X]
. Enmerge()
= merge(X, Y, all.x=TRUE) - RIGHT OUTER: en DT =
X[Y]
. Enmerge()
= merge(X, Y, all.y=TRUE) - FULL OUTER: en DT no se puede. En
merge()
= merge(X, Y, all=TRUE)
7.4.1 INNER
Sólo retorna las filas de df1
que tienen una equivalencia en df2
,
7.4.2 LEFT OUTER
Retorna todas las columnas de df1
y df2
, pero sólo retorna todas las filas de df1
.
7.4.3 RIGHT OUTER
Retorna todas las columnas de df2
y df1
, pero sólo retorna todas las filas de df2
.
7.4.4 FULL OUTER
Retorna todas las columnas de df1
y df2
, y todas las filas de df1
y df2
.
7.4.5 setkey()
y setkeyv()
Si queremos usar la notación data.table()
sin usar el argumento on
podemos usar la función setkey()
para decirle a cada “data.table” cual es la “clave” de la base de datos:
df1 <- data.table(x = c("X", "Z"), y = 2:1)
df2 <- data.table(x = c("X", "V"), a = 10, b = "a")
setkey(df1,x)
setkey(df2,x)
df1[df2]
## x y a b
## 1: V NA 10 a
## 2: X 2 10 a
df2[df1]
## x a b y
## 1: X 10 a 2
## 2: Z NA <NA> 1
Y ahora, la selección de filas también es directa en base a la “key”
Si queremos pasarle varias columnas para ordenar, usaremos la función setkeyv()
7.4.6 ANTI JOIN
(df1 <- data.table(V1 = c(1, 1, 3, 4), V2 = 1:4))
## V1 V2
## 1: 1 1
## 2: 1 2
## 3: 3 3
## 4: 4 4
(df2 <- data.table(V1 = c(1, 1, 2), V3 = c("a", "b", "a")))
## V1 V3
## 1: 1 a
## 2: 1 b
## 3: 2 a
df2[!df1,,on=c("V1")]
## V1 V3
## 1: 2 a
# y del otro lado
df1[!df2,,on=c("V1")]
## V1 V2
## 1: 3 3
## 2: 4 4
7.5 Funciones interesantes
7.5.1 Familia set*()
7.5.1.1 Renombrar variables setnames()
setnames(IRIS, "sepal_area", "Area_de_Sepalo")
IRIS[1:2]
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species i col Area_de_Sepalo petal_area
## 1: 5.1 3.5 1.4 0.2 setosa 1 A 17.85 0.28
## 2: 4.9 3.0 1.4 0.2 setosa 1 B 14.70 0.28
“sepal_area” pasa a llamarse “Area_de_Sepalo” :)
7.5.1.2 Reordenar columnas setcolorder()
7.5.1.3 Ordenar con setorder()
y setorderv()
setorder(IRIS, "Petal.Width") ## ordenar por "Petal.Width"
IRIS[1:5]
## Species Area_de_Sepalo Sepal.Length Sepal.Width Petal.Length Petal.Width i col petal_area
## 1: setosa 15.19 4.9 3.1 1.5 0.1 1 B 0.15
## 2: setosa 14.40 4.8 3.0 1.4 0.1 1 A 0.14
## 3: setosa 12.90 4.3 3.0 1.1 0.1 1 B 0.11
## 4: setosa 21.32 5.2 4.1 1.5 0.1 1 A 0.15
## 5: setosa 17.64 4.9 3.6 1.4 0.1 1 B 0.14
setorderv(IRIS, c("Petal.Length","Petal.Width")) ## ordenar por dos variables
IRIS[1:5]
## Species Area_de_Sepalo Sepal.Length Sepal.Width Petal.Length Petal.Width i col petal_area
## 1: setosa 16.56 4.6 3.6 1.0 0.2 1 A 0.20
## 2: setosa 12.90 4.3 3.0 1.1 0.1 1 B 0.11
## 3: setosa 23.20 5.8 4.0 1.2 0.2 1 A 0.24
## 4: setosa 16.00 5.0 3.2 1.2 0.2 1 B 0.24
## 5: setosa 15.04 4.7 3.2 1.3 0.2 1 A 0.26
7.5.1.4 Ordenar con setkey()
y setkeyv()
Como ya vimos antes, estas funciones, ordenan de forma “oficial” los datos.
setkey(IRIS, "Petal.Width") ## ordenar por "Petal.Width"
str(IRIS)
## Classes ‘data.table’ and 'data.frame': 150 obs. of 9 variables:
## $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ Area_de_Sepalo: num 12.9 14.4 17.6 15.2 21.3 ...
## $ Sepal.Length : num 4.3 4.8 4.9 4.9 5.2 4.6 5.8 5 4.7 5.5 ...
## $ Sepal.Width : num 3 3 3.6 3.1 4.1 3.6 4 3.2 3.2 3.5 ...
## $ Petal.Length : num 1.1 1.4 1.4 1.5 1.5 1 1.2 1.2 1.3 1.3 ...
## $ Petal.Width : num 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.2 0.2 ...
## $ i : int 1 1 1 1 1 1 1 1 1 1 ...
## $ col : chr "B" "A" "B" "B" ...
## $ petal_area : num 0.11 0.14 0.14 0.15 0.15 0.2 0.24 0.24 0.26 0.26 ...
## - attr(*, ".internal.selfref")=<externalptr>
## - attr(*, "sorted")= chr "Petal.Width"
setkeyv(IRIS, c("Petal.Length","Petal.Width")) ## ordenar por dos variables
str(IRIS)
## Classes ‘data.table’ and 'data.frame': 150 obs. of 9 variables:
## $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ Area_de_Sepalo: num 16.6 12.9 23.2 16 15 ...
## $ Sepal.Length : num 4.6 4.3 5.8 5 4.7 5.5 4.4 4.4 5 4.5 ...
## $ Sepal.Width : num 3.6 3 4 3.2 3.2 3.5 3 3.2 3.5 2.3 ...
## $ Petal.Length : num 1 1.1 1.2 1.2 1.3 1.3 1.3 1.3 1.3 1.3 ...
## $ Petal.Width : num 0.2 0.1 0.2 0.2 0.2 0.2 0.2 0.2 0.3 0.3 ...
## $ i : int 1 1 1 1 1 1 1 1 1 1 ...
## $ col : chr "A" "B" "A" "B" ...
## $ petal_area : num 0.2 0.11 0.24 0.24 0.26 0.26 0.26 0.26 0.39 0.39 ...
## - attr(*, ".internal.selfref")=<externalptr>
## - attr(*, "sorted")= chr [1:2] "Petal.Length" "Petal.Width"
7.5.2 fcase
“CASE” - “WHEN” de data.table
. Funciona de esta manera: fcase(test, TRUE, test, TRUE, ..., default=NA)
Volvemos a la base de datos “gapminder”. Vamos a calificar entre países buenos y malos en base a su esperanza de vida.
df <- gapminder
setDT(df)
df[,.(fcase(lifeExp > mean(lifeExp),"good",
lifeExp < mean(lifeExp),"bad"))]
## V1
## 1: bad
## 2: bad
## 3: bad
## 4: bad
## 5: bad
## ---
## 1700: good
## 1701: good
## 1702: bad
## 1703: bad
## 1704: bad
df[,.(fcase(lifeExp > mean(lifeExp),"good",
default = "bad"))]
## V1
## 1: bad
## 2: bad
## 3: bad
## 4: bad
## 5: bad
## ---
## 1700: good
## 1701: good
## 1702: bad
## 1703: bad
## 1704: bad
Y si queremos poner más de una condición:
df[,.(fcase(lifeExp > mean(lifeExp) & gdpPercap > mean(gdpPercap),"good",
lifeExp < mean(lifeExp) & gdpPercap < mean(gdpPercap),"bad",
default="medium"))]
## V1
## 1: bad
## 2: bad
## 3: bad
## 4: bad
## 5: bad
## ---
## 1700: medium
## 1701: medium
## 1702: bad
## 1703: bad
## 1704: bad
7.5.2.1 Ejercicio
Cread una nueva columna con el calificativo “good” or “bad” en base a la esperanza de vida.
7.5.3 fifelse
Funciona de esta manera: fifelse(test, yes, no, na=NA)
df[,.(fifelse(lifeExp > mean(lifeExp),"good","bad"))]
## V1
## 1: bad
## 2: bad
## 3: bad
## 4: bad
## 5: bad
## ---
## 1700: good
## 1701: good
## 1702: bad
## 1703: bad
## 1704: bad
7.5.3.1 Ejercicio
Poned el calificativo “good” or “bad” comparando las medias de esperanza de vida de cada continenete para 2007. Osea, usad By = continent
7.5.4 rbindlist
Funciona de esta manera: rbindlist( l , use.names = TRUE, fill = FALSE)
Argumentos:
l
: una lista que contiene objetos data.table, data.frame o lista.use.names
:TRUE
junta por los nombres de las columnas que hacen “match”.FALSE
las junta por posición.fill
:TRUE
rellena usando NAs.
Tablas con las mismas variables
(DT1 = data.table(A=1:3,B=letters[1:3]))
## A B
## 1: 1 a
## 2: 2 b
## 3: 3 c
(DT2 = data.table(A=4:5,B=letters[4:5]))
## A B
## 1: 4 d
## 2: 5 e
l = list(DT1,DT2)
rbindlist(l)
## A B
## 1: 1 a
## 2: 2 b
## 3: 3 c
## 4: 4 d
## 5: 5 e
Tablas con variables diferentes
7.5.5 duplicated
Esta función nos da un vector lógico sobre las filas que hay duplicadas
Funciona de esta manera: duplicated(x, fromLast=FALSE, by=seq_along(x), ...)
x
: una data.table.fromLast
: dirección en la que te dice la observación que se duplica.by
: las variables en las que fijarse para ver duplicados.
(DT <- data.table(A = rep(1:3, each=4), B = rep(1:4, each=3),
C = rep(1:2, 6), key = "A,B"))
## A B C
## 1: 1 1 1
## 2: 1 1 2
## 3: 1 1 1
## 4: 1 2 2
## 5: 2 2 1
## 6: 2 2 2
## 7: 2 3 1
## 8: 2 3 2
## 9: 3 3 1
## 10: 3 4 2
## 11: 3 4 1
## 12: 3 4 2
duplicated(DT)
## [1] FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE
duplicated(DT, by="B")
## [1] FALSE TRUE TRUE FALSE TRUE TRUE FALSE TRUE TRUE FALSE TRUE TRUE
duplicated(DT, by=c("A", "C"))
## [1] FALSE FALSE TRUE TRUE FALSE FALSE TRUE TRUE FALSE FALSE TRUE TRUE
7.5.6 unique
Funciona igual que duplicated
, pero nos da la DT sin duplicados
unique(DT)
## A B C
## 1: 1 1 1
## 2: 1 1 2
## 3: 1 2 2
## 4: 2 2 1
## 5: 2 2 2
## 6: 2 3 1
## 7: 2 3 2
## 8: 3 3 1
## 9: 3 4 2
## 10: 3 4 1
unique(DT, by="B")
## A B C
## 1: 1 1 1
## 2: 1 2 2
## 3: 2 3 1
## 4: 3 4 2
unique(DT, by=c("A", "C"))
## A B C
## 1: 1 1 1
## 2: 1 1 2
## 3: 2 2 1
## 4: 2 2 2
## 5: 3 3 1
## 6: 3 4 2
7.5.7 uniqueN
Esta función nos da el número de niveles diferentes en la variable. Funciona muy parecido a unique
7.5.8 between
Esta función nos da un vector lógico. TRUE
si el valor está entre los valores que proporcionemos (lower <= x & x <= upper).
Funciona de esta manera: between(x, lower, upper, incbounds=TRUE)
x
: cualquier variable a la que le podamos aplicar un<=
.lower
: el corte por debajo.upper
: el corte por encima.
También puede usarse%between%
7.5.9 fsort
Esta función nos ordena un vector en orden ascendente os descendente:
Funciona de esta manera: fsort(x, decreasing = FALSE, na.last = FALSE)
x
: un vectordecreasing
:TRUE
ordena de forma decreciente.FALSE
, ascendiente.na.last
: donde ponemos los NA.TRUE
al final,FALSE
al principio.
(x=runif(10))
## [1] 0.1859589 0.8206501 0.7289161 0.2601126 0.2932034 0.4763283 0.6727095
## [8] 0.3047416 0.9650763 0.9364433
fsort(x)
## [1] 0.1859589 0.2601126 0.2932034 0.3047416 0.4763283 0.6727095 0.7289161
## [8] 0.8206501 0.9364433 0.9650763
fsort(x,decreasing = T)
## [1] 0.9650763 0.9364433 0.8206501 0.7289161 0.6727095 0.4763283 0.3047416
## [8] 0.2932034 0.2601126 0.1859589
7.5.10 like
Esta función nos busca secuencias de letras (strings) en el vector. Se usa para vectores de tipo nombre generalmente
Funciona de esta manera: like(vector, pattern, ignore.case = FALSE)
vector
: pues eso, un vector.pattern
: el patrón de letras que queremos buscar
ignore.case
: para ver si importa si es mayúscula o no.
DT = data.table(Name=c("Mary","George","Martha","Manuel"),
Salary=c(2,3,4,17))
DT[like(Name,"Ma")]
## Name Salary
## 1: Mary 2
## 2: Martha 4
## 3: Manuel 17
DT[like(Name,"ma")]
## Empty data.table (0 rows and 2 cols): Name,Salary
DT[like(Name,"ma",ignore.case=T)]
## Name Salary
## 1: Mary 2
## 2: Martha 4
## 3: Manuel 17
DT[like(Name,"mar",ignore.case=T)]
## Name Salary
## 1: Mary 2
## 2: Martha 4
7.5.11 rowid
y rowidv
Esta función genera IDs differentes para cada fila dentro de un grupo.
(DT = data.table(x=c(20,10,10,30,30,20), y=c("a", "a", "a", "b", "b", "b"), z=1:6+.1))
## x y z
## 1: 20 a 1.1
## 2: 10 a 2.1
## 3: 10 a 3.1
## 4: 30 b 4.1
## 5: 30 b 5.1
## 6: 20 b 6.1
rowid(DT$x)
## [1] 1 1 2 1 2 2
rowidv(DT, cols="x")
## [1] 1 1 2 1 2 2
rowid(DT$x, prefix="grupo") # prefijo
## [1] "grupo1" "grupo1" "grupo2" "grupo1" "grupo2" "grupo2"
rowid(DT$x, DT$y)
## [1] 1 1 2 1 2 1
rowidv(DT, cols=c("x","y"))
## [1] 1 1 2 1 2 1
DT[, id := rowid(x,y)]
## x y id
## 1: 20 a 1
## 2: 10 a 1
## 3: 10 a 2
## 4: 30 b 1
## 5: 30 b 2
## 6: 20 b 1