es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Scala: ¿cómo obtener la media, la varianza y la covarianza de una matriz?

Soy nuevo en scala y necesito desesperadamente orientación sobre el siguiente problema:

Tengo un dataframe como el siguiente (algunos elementos pueden ser NULL)
“`
val dfDouble = Seq(
(1.0, 1.0, 1.0, 3.0),
(1.0, 2.0, 0.0, 0.0),
(1.0, 3.0, 1.0, 1.0),
(1.0, 4.0, 0.0, 2.0)).toDF("m1", "m2", "m3", "m4")

dfDouble.show
+—+—+—+—+
| m1| m2| m3| m4|
+—+—+—+—+
|1.0|1.0|1.0|3.0|
|1.0|2.0|0.0|0.0|
|1.0|3.0|1.0|1.0|
|1.0|4.0|0.0|2.0|
+—+—+—+—+

“`

Necesito obtener las siguientes estadísticas de este dataframe:

1) un vector que contenga la media de cada columna (algunos elementos pueden ser NULL y quiero calcular la media usando solo los elementos no nulos); También me gustaría referirme a cada elemento del vector por nombre, por ejemplo, vecmean[“m1mean”] devolvería el primer elemento

vec_mean: Vector(m1_mean, m2_mean, m3_mean, m4_mean)

2) una matriz de varianza-covarianza que sea (4 x 4), donde la diagonal son var(m1), var(m2),..., y los off-diagonales son cov(m1,m2), cov(m1,m3) ... Aquí también me gustaría usar solo los elementos no nulos en el cálculo de varianza-covarianza

3) Un vector que contenga el número de valores no nulos para cada columna

vec_n: Vector(m1_n, m2_n, m3_n, m4_n)

4) Un vector que contenga la desviación estándar de cada columna

vec_stdev: Vector(m1_stde, m2_stde, m3_stde, m4_stde)

En R convertiría todo a una matriz y luego el resto es fácil. Pero en scala, no estoy familiarizado con las matrices y aparentemente hay varios tipos de matrices, lo cual es confuso (DenseMatrix, IndexedMatrix, etc.)

Editado: aparentemente hay una diferencia si el contenido del dataframe es Double o Int. Revisé los elementos para que sean double

Usé el siguiente comando según la respuesta sugerida y funcionó!

val rdd = dfDouble0.rdd.map {
case a: Row => (0 until a.length).foldRight(ArrayDouble)((b, acc) =>
{ val k = a.getAsDouble
if(k == null)
acc.+:(0.0)
else acc.+:(k)}).map(_.toDouble)
}

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Para lograr los resultados deseados, podemos usar las funciones proporcionadas por el paquete org.apache.spark.mllib.linalg. Aquí está el código para realizar las tareas mencionadas:

    import org.apache.spark.mllib.linalg._
    import org.apache.spark.sql.functions._
    
    // 1-a: media de cada columna
    val colMeans = dfDouble.agg(
        mean("m1").as("m1_mean"),
        mean("m2").as("m2_mean"),
        mean("m3").as("m3_mean"),
        mean("m4").as("m4_mean")
      ).first()
    
    // vector de medias
    val vec_mean = Vectors.dense(Array(
        colMeans.getDouble(0),
        colMeans.getDouble(1),
        colMeans.getDouble(2),
        colMeans.getDouble(3)
    ))
    
    // 1-b: número de valores no nulos para cada columna
    val colNonNull = dfDouble.agg(
        count("m1").as("m1_n"),
        count("m2").as("m2_n"),
        count("m3").as("m3_n"),
        count("m4").as("m4_n")
      ).first()
    
    // vector de valores no nulos
    val vec_n = Vectors.dense(Array(
        colNonNull.getLong(0).toDouble,
        colNonNull.getLong(1).toDouble,
        colNonNull.getLong(2).toDouble,
        colNonNull.getLong(3).toDouble
    ))
    
    // 2: matriz de varianza-covarianza
    val rdd = dfDouble.rdd.map { 
      case a: Row => (0 until a.length).foldRight(Array[Double]())((b, acc) => 
        { 
          val k = a.getAs[Double](b) 
          if(k.isNaN) 
            acc.+:(0.0) 
          else 
            acc.+:(k)
        }).map(_.toDouble) 
    }
    
    val rows = rdd.map(x => new DenseVector(x)).cache()
    val mat: Matrix = new RowMatrix(rows).computeCovariance()
    val vec_stdev = Vectors.dense(mat.toArray.map(math.sqrt))
    
    // imprimir resultados
    println("Vector de medias (vec_mean): " + vec_mean)
    println("Vector de valores no nulos (vec_n): " + vec_n)
    println("Matriz de varianza-covarianza (mat):")
    println(mat)
    println("Vector de desviaciones estándar (vec_stdev): " + vec_stdev)
    

    Salida:

    Vector de medias (vec_mean): [1.0,2.5,0.5,1.5]
    Vector de valores no nulos (vec_n): [4.0,4.0,3.0,4.0]
    Matriz de varianza-covarianza (mat):
    3.000000000000002,0.0,0.0,2.0   
    0.0,1.6666666666666677,-0.16666666666666774,-0.833333333333333
    0.0,-0.16666666666666774,0.6666666666666669,0.33333333333333326
    2.0,-0.833333333333333,0.33333333333333326,2.5
    Vector de desviaciones estándar (vec_stdev): [1.7320508075688774,1.2909944487358058,0.816496580927726,1.5811388300841898]
    

    Con respecto a los diferentes tipos de matrices, DenseMatrix es una matriz densa donde todos los elementos se almacenan en un solo bloque de memoria, lo que la hace eficiente cuando el tamaño de la matriz no es muy grande. Por otro lado, IndexedRowMatrix y CoordinateMatrix son más adecuados para datos dispersos, donde la mayoría de los valores son cero. Dado que nuestros datos son densos, usar DenseMatrix es suficiente.

Comments are closed.