lunes, 27 de abril de 2020

R en Español: Obtener nombres de renglones con funcion row.names

Si deseo obtener los nombres de los renglones de mi dataframe puedo utilizar la función row.names de la paquetería básica de R y RStudio. Ejemplo:

Si mi dataframe consta de 5 renglones y 2 columnas:
> my_data <- data.frame(c("casa", "perro", "gato", "taza", "noche"), c(4,5,6,7,8))
Y quiero obtener únicamente los nombres de los renglones, que en este caso serían "1, 2, 3, 4, y 5", necesito llamar a la función row.names que está disponible en la paquetería básica de R y RStudio.
> nombres_renglones <- row.names(my_data)
> nombres_renglones
[1] "1" "2" "3" "4" "5"
Como se puede corroborar, la función row.names regresa como resultado los nombres de los reglones como palabras o strings, por lo que si sólo se quieren tener los nombres de los renglones como números es necesario utilizar la función "de-string", disponible AQUÍ.

R en Español: Convertir una lista en un dataframe

Cuando se trabaja con listas, hay veces que se necesita volver al formato del dataframe.

Por ejemplo, tengo la siguiente lista de 3 elementos llamada "mi_lista":

elemento_1 <- c(1,2,3,4,5)
elemento_2 <- c(6,7,8,9,10)
elemento_3 <- c(11,12,13,14,15)

mi_lista <- list(elemento_1, elemento_2, elemento_3)

Después de trabajar con esta lista, deseo convertirla en un dataframe.

Tengo dos opciones. Si quiero que todos los elementos queden en una sola columna, puedo utilizar la función unlist.

mi_dataframe <- as.data.frame(unlist(mi_lista))
mi_dataframe
   unlist(mi_lista)
1                 1
2                 2
3                 3
4                 4
5                 5
6                 6
7                 7
8                 8
9                 9
10               10
11               11
12               12
13               13
14               14
15               15
O bien, puedo utilizar do.call y rbind (o cbind) para armar mi dataframe ordenado.

mi_dataframe <- data.frame(do.call("rbind", mi_lista))
mi_dataframe
  X1 X2 X3 X4 X5
1  1  2  3  4  5
2  6  7  8  9 10
3 11 12 13 14 15

R en español: Redondear un vector de números sin alterar la suma total del vector

En ocasiones necesitamos redondear pero deseamos mantener ciertas propiedades. En este caso, existe una función para R que permite redondear una serie de números sin que se altere la suma total de la misma.

Por ejemplo, supongamos que tenemos el siguiente vector:

x = c(1.5, 1.2, 1.3)

La suma total de este vector es 4, pero al momento de redondear es probable obtener como resultado este vector:

x = c(2, 1, 1)

O bien, este otro:

x = c(1, 1, 1)

Al trabajar con únicamente 3 números es fácil resolver el dilema de qué hacer para redondear respetando la suma total del vector (es decir, 4), sin embargo, al trabajar con mucho más números el problema se torna un poco más complicado.

La manera más simple de resolver esto y de evitar el roundoff error es con la siguiente función:

smart.round <- function(x) {
  y <- floor(x)
  indices <- tail(order(x-y), round(sum(x)) - sum(y))
  y[indices] <- y[indices] + 1
  y
}
v
# [1] 2.655087 3.721239 5.728534 9.082078 3.813063
sum(v)
# [1] 25
smart.round(v)
# [1] 2 4 6 9 4
sum(smart.round(v))
# [1] 25
Si lo que se desea es redondear respetando además un cierto número de decimales, se puede usar esta otra función:

smart.round <- function(x, digits = 0) {
  up <- 10 ^ digits
  x <- x * up
  y <- floor(x)
  indices <- tail(order(x-y), round(sum(x)) - sum(y))
  y[indices] <- y[indices] + 1
  y / up
}
Este código y más detalles sobre el mismo pueden consultarse en:
https://stackoverflow.com/questions/32544646/round-vector-of-numerics-to-integer-while-preserving-their-sum

R en Español: Función para convertir caracteres en números o destring

Hay ocasiones en las que tenemos números almacenados como palabras o strings.

Por ejemplo, si mi conjunto de datos es como el siguiente:
> df1 <- c("1", "2", "3", "4", "5")
> df2 <- c("6", "7", "8", "9", "10")
no seré capaz de sumar df1 + df2. Obtendré este error:
> df1+df2
Error in df1 + df2 : non-numeric argument to binary operator
Esto se debe a que los números en df1 y df2 no son reconocidos como números, sino como palabras. ¿Por qué? Pues al estar entre comillas, R los reconoce como palabras.

Para convertirlos en números necesitamos usar la función destring:
destring <- function(x,keep="0-9.-") {
  return( as.numeric(gsub(paste("[^",keep,"]+",sep=""),"",x)) )
}
De modo en el que al aplicarla a nuestros conjuntos de datos df1 y df2, obtenemos:
> df1 <- destring(df1)
> df2 <- destring(df2)
> df1+df2
[1]  7  9 11 13 15
Así, df1 y df2 se convirtieron en números con los que se pueden realizar operaciones sin obtener el error non-numeric argument to binary operator.

La función destring fue tomada del siguiente post en Stackoverflow: https://stackoverflow.com/questions/9739518/r-cleaning-up-a-character-and-converting-it-into-a-numeric/9740635#9740635

R en español: Unir columnas o renglones de data frames de dos listas distintas

Trabajar con listas ahorra mucho tiempo y lineas de código, pero hay ocasiones en las que las soluciones usuales para unir data frames no resultan como uno espera.

Cuando se desea unir dos data frames sólo es necesario utilizar la función append o bien, emplear las funciones cbind y rbind según se requiera. El problema surge cuando queremos unir todos los data frames de una lista con los de otra lista.

Por ejemplo, pensemos que tenemos estas dos listas:

lista1 <- list(df1, df2)
lista2 <- list(df3, df4)

Si queremos generar una nueva lista con las columnas combinadas de los data frames de las dos listas sólo necesitamos hacer lo siguiente.

1. Supongamos que tenemos estas dos listas, la A y la B:

num = 10
A<-list()
B<-list()
for (j in 1:num){
    A[[j]] <- as.data.frame(matrix(seq(1:9),3,3))
    B[[j]] <- as.data.frame(matrix(seq(10:18),3,3))
}

combo1<-list()
for (i in 1:num){
    combo1[[i]] <-rbind(A[[i]], B[[i]])  
}
2. Ahora sólo necesitamos usar mapply con la función cbind (para unir columnas) o rbind (para unir renglones).

## Make this a more _minimal_ reproducible example
A <- A[1:2]
B <- B[1:2]

## Override default attempt to reduce results to a vector, matrix, or other array
mapply("rbind", A, B, SIMPLIFY=FALSE)
# [[1]]
#   V1 V2 V3
# 1  1  4  7
# 2  2  5  8
# 3  3  6  9
# 4  1  4  7
# 5  2  5  8
# 6  3  6  9
# 
# [[2]]
#   V1 V2 V3
# 1  1  4  7
# 2  2  5  8
# 3  3  6  9
# 4  1  4  7
# 5  2  5  8
# 6  3  6  9
Para más información sobre este código revisar: https://stackoverflow.com/questions/14329264/mapply-and-two-lists

R en Español: Obtener nombres de renglones con funcion row.names

Si deseo obtener los nombres de los renglones de mi dataframe puedo utilizar la función row.names de la paquetería básica de R y RStudio. ...