Obtener información básica de los DataFrames de Julia (12ª parte – ¡Hola Julia!)

Publicado el 20 agosto 2020 por Daniel Rodríguez @analyticslane

En la entrada anterior hemos visto el funcionamiento básico de los DataFrames en Julia. Una herramienta que es clave para trabajar con datos de forma eficiente. Algo que pueden confirma los usuarios acostumbrados a trabajar tanto en R como con la librería Pandas, donde estos objetos son clave para el trabajo diario. En esta entrada vamos a ver cómo obtener alguna información básica de los DataFrames de Julia.

Tamaño de los DataFrames

Al importar un DataFrame uno de los puntos básicos que suele ser interesante conocer es el tamaño de este. Tanto el número de filas como el número de columnas. Para lo que se puede crear la función size(). Por ejemplo, si creamos un DataFrame como hemos visto en la entrada anterior podemos obtener la información.

df = DataFrame(A = [1, 2, 3, 4],
    B = [1.0, missing, 3.9, 2.2],
    C = ["a", "b", "c", "a"])
│ Row │ A     │ B        │ C      │
│     │ Int64 │ Float64? │ String │
├─────┼───────┼──────────┼────────┤
│ 1   │ 1     │ 1.0      │ a      │
│ 2   │ 2     │ missing  │ b      │
│ 3   │ 3     │ 3.9      │ c      │
│ 4   │ 4     │ 2.2      │ a      │

En este caso hemos creado un DataFrame con una columna de tipo entero, otra de tipo real y una con cadena de texto. Hay que notar que en la columna B, la que contiene los reales, se ha utilizado un tipo especial missing con el que se representa los datos faltantes. Un tipo de dato especial que existe en Julia y veremos en más detalle en la próxima entrada. Cada una de las columnas tiene cuatro filas, por lo que el Dataframe es de 4 por 3. Siendo esto lo que devuelve la función size() en una tupla.

size(df) # (4, 3)

En el caso de que solamente necesitamos conocer el número de filas o columnas se puede emplear las funciones nrow() y ncol() respectivamente. Aunque también se le puede pasar a la función size() como segundo parámetro la dimensión, 1 para las filas y 2 para las columnas.

nrow(df) # 4
ncol(df) # 3

size(df, 1) # Equivalente a nrow(df)
size(df, 2) # Equivalente a ncol(df)

Nombres de las columnas

Una de las ventajas que tienen los DataFrames frente a las matrices es que las columnas tienen nombre, lo que hace que sea más fácil trabajar con ellas al saber lo que contiene cada una. En Julia, los nombres de las columnas se pueden obtener mediante la función names(), obteniendo como resultado un vector de cadenas de texto.

names(df)
3-element Array{String,1}:
 "A"
 "B"
 "C"

Otra opción es obtener los símbolos de las columnas, lo que se puede obtener mediante la función propertynames() Obteniéndose en este caso un vector de símbolos.

propertynames(x)
3-element Array{Symbol,1}:
 :A
 :B
 :C

Tipos de datos en las columnas

A la hora de trabajar con objetos DataFrame suele ser interesante conocer el tipo de dato de cada una de las columnas. Ya que no es lo mismo una columna con enteros, caracteres o cadenas de texto. Para obtener esta información se puede utilizar la función eltype() sobre cada una de las columnas del DataFrame. Siendo necesario para ello usar la función eachcol() como se muestra en el siguiente ejemplo.

eltype.(eachcol(df))
3-element Array{Type,1}:
 Int64
 Union{Missing, Float64}
 String

Información básica sobre los datos

Hasta ahora solamente hemos visto algunas funciones para obtener información de la estructura del DataFrame, no del contenido. Para obtener una información básica del contenido del DataFrame se puede obtener con la función describe(). Esta función nos devuelve el símbolo, la media, el valor mínimo, la mediana, el valor máximo, el número de valores únicos, el número de valores perdidos y el tipo de dato de la columna.

describe(df)
3×8 DataFrame
│ Row │ variable │ mean    │ min │ median │ max │ nunique │ nmissing │ eltype                  │
│     │ Symbol   │ Union...  │ Any │ Union... │ Any │ Union...  │ Union...   │ Type                    │
├─────┼──────────┼─────────┼─────┼────────┼─────┼─────────┼──────────┼─────────────────────────┤
│ 1   │ A        │ 2.5     │ 1   │ 2.5    │ 4   │         │          │ Int64                   │
│ 2   │ B        │ 2.36667 │ 1.0 │ 2.2    │ 3.9 │         │ 1        │ Union{Missing, Float64} │
│ 3   │ C        │         │ a   │        │ c   │ 3       │          │ String                  │

Por otro lado, para ver solamente unas pocas filas de un DataFrame se puede emplear la función first() con el DataFrame y el número de filas que deseamos ver. Una función que por defecto solo muestra la primera fila.

df_huge = DataFrame(rand(1:5, 1000, 5))
first(df_huge, 5)
5×5 DataFrame
│ Row │ x1    │ x2    │ x3    │ x4    │ x5    │
│     │ Int64 │ Int64 │ Int64 │ Int64 │ Int64 │
├─────┼───────┼───────┼───────┼───────┼───────┤
│ 1   │ 2     │ 1     │ 5     │ 5     │ 3     │
│ 2   │ 2     │ 1     │ 5     │ 3     │ 2     │
│ 3   │ 1     │ 2     │ 1     │ 2     │ 5     │
│ 4   │ 1     │ 2     │ 1     │ 1     │ 4     │
│ 5   │ 4     │ 2     │ 1     │ 1     │ 3     │

Por otro lado, para ver las últimas filas se puede usar la función last().

Acceso a los datos

En Julia es posible acceder a cada una de las columnas de un DataFrame empleando tanto la posición como por nombre o el símbolo. Pudiéndose además emplear tanto la notación con corchetes que se utiliza para acceder los elementos de las matrices, como la notación punto. Así, para acceder a la primera columna (la que se ha llamado A) del DataFrame de ejemplo se puede utilizar cualquiera de las siguientes opciones.

df.A
df."A"
df[:, "A"]
df[:, 1]
df[!, 1]

En los tres primeros casos se indica que nos devuelve la columna cuyo nombre es A. Nótese que en este caso se puede usar tanto el nombre como una propiedad como unas cadenas de texto cuando se emplea la notación punto. Aunque solamente se puede usar una cadena de texto cuando se usa la notación corchete. Por otro lado, en el cuarto y quinto ejemplo se indica que devuelva la primera columna, que en el ejemplo es la columna A.

En este ejemplo se puede ver además que hay dos símbolos para indicar que toda la columna: : y !. Dos símbolos que no son exactamente iguales. Algo que se puede ver comparado los objetos que se obtienen en cada caso.

df[:, 1] === df[:, 1] # false
df[!, 1] === df[!, 1] # true

Cuando se usa : los objetos son diferentes, lo que indica que se crea una copia del vector. Por otro lado cuando se compara los objetos que se obtienen con ! se puede ver que es exactamente el mismo. Algo que tiene consecuencias en caso de que se modifique el contenido de las columnas, al usar : nunca se modifica el original, pero sí con !.

Esto también tiene consecuencias si se agrega una nueva columna. Si se asigna un vector en una columna con : se crea una copia, mientras que si se usa ! lo que se produce es la asignación del vector. Algo que se puede comprobar como se ha visto antes con el operador ===.

x = [10, 11, 12, 13]

df[!, "D"] = x
df[:, "E"] = x

df.D === x # true
df.E === x # false

Finalmente, si se desea forzar la asignación se puede usar el operador de asignación .= en lugar de =.

df[!, "F"] .= x
df[:, "G"] .= x

df.F === x # true
df.G === x # true

Múltiples opciones para obtener información básica de los DataFrames de Julia

En esta ocasión se ha visto que existen múltiples opciones para obtener información básica de los DataFrames de Julia. Algo que muestra lo importante que son estos objetos para realizar análisis de datos en Julia.