You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将MLlib矩阵转为Spark DataFrame?Zeppelin中如何美观展示相关系数?

嘿,我来帮你搞定这两个Spark相关的问题:

1. 如何将MLlib矩阵转换为Spark DataFrame?

MLlib里的矩阵主要分稠密矩阵(DenseMatrix)和稀疏矩阵(SparseMatrix),转换方式略有不同,我给你分别举Scala的例子(Spark常用Scala开发,Python思路类似):

对于稠密矩阵(DenseMatrix)

如果你的矩阵是DenseMatrix类型,可以先把它转成二维数组,再映射成Row对象,最后结合自定义Schema创建DataFrame:

import org.apache.spark.ml.linalg.DenseMatrix
import org.apache.spark.sql.{Row, SparkSession}
import org.apache.spark.sql.types.{DoubleType, StructField, StructType}

val spark = SparkSession.builder().appName("MatrixToDF").getOrCreate()

// 示例稠密矩阵
val denseMat = new DenseMatrix(3, 2, Array(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))

// 生成Schema:列名可以自定义,比如col_0, col_1...
val schema = StructType((0 until denseMat.numCols).map(colIdx => StructField(s"col_$colIdx", DoubleType)))

// 将矩阵转为Row集合
val rows = (0 until denseMat.numRows).map(rowIdx => Row.fromSeq(denseMat.row(rowIdx).toArray))

// 创建DataFrame
val df = spark.createDataFrame(spark.sparkContext.parallelize(rows), schema)

df.show()

对于稀疏矩阵(SparseMatrix)

如果是稀疏矩阵,你可以选择两种转换方式:

  • 方式一:转成稠密矩阵再按上面的方法处理(适合小矩阵)
  • 方式二:提取非零元素的坐标和值,生成三列(行索引、列索引、值)的长格式DataFrame,更节省空间:
import org.apache.spark.ml.linalg.SparseMatrix
import org.apache.spark.sql.Row
import org.apache.spark.sql.types.{IntegerType, DoubleType, StructField, StructType}

// 示例稀疏矩阵
val sparseMat = new SparseMatrix(3, 2, Array(0, 2, 3), Array(0, 1, 0), Array(1.0, 2.0, 3.0))

// 提取非零元素
val nonZeroRows = sparseMat.nonZero.map { case (i, j, v) => Row(i, j, v) }

// 定义Schema
val sparseSchema = StructType(Seq(
  StructField("row_idx", IntegerType),
  StructField("col_idx", IntegerType),
  StructField("value", DoubleType)
))

val sparseDF = spark.createDataFrame(spark.sparkContext.parallelize(nonZeroRows.toSeq), sparseSchema)

sparseDF.show()
2. Zeppelin中美观打印50列的相关系数矩阵

你说转成每值一列的DataFrame用z.show()会被截断,确实50列的宽表在Zeppelin里默认显示会很受限,这里有几个更直接的方法:

方法一:转成“特征对-相关系数”的长格式DataFrame

把宽表转成长表,每一行代表一对特征的相关系数,这样既不会截断,也更方便查看特定特征的相关性:

import org.apache.spark.ml.linalg.Matrix
import org.apache.spark.sql.Row
import org.apache.spark.sql.types.{StringType, DoubleType, StructField, StructType}

// 假设你已经计算得到相关系数矩阵corrMat,以及特征名数组featureNames
val corrMat: Matrix = ...
val featureNames: Array[String] = ... // 比如Array("feat1", "feat2", ..., "feat50")

// 生成所有特征对的相关系数行(可选i<=j避免重复显示对称系数)
val corrRows = for {
  i <- 0 until corrMat.numRows
  j <- 0 until corrMat.numCols
  if i <= j
} yield Row(featureNames(i), featureNames(j), corrMat(i, j))

// 创建长格式DataFrame
val corrDF = spark.createDataFrame(spark.sparkContext.parallelize(corrRows), 
  StructType(Seq(
    StructField("feature_a", StringType),
    StructField("feature_b", StringType),
    StructField("correlation", DoubleType)
  ))
)

// Zeppelin中显示,不会截断
corrDF.show(truncate = false)

方法二:用Zeppelin的%html魔法渲染成完整表格

如果你还是想保留宽表的形式,可以把矩阵转成HTML表格,Zeppelin支持直接渲染HTML,这样能完整显示50列:

// 生成HTML表格字符串
val htmlTable = s"""
<table border="1" cellpadding="4" cellspacing="0">
  <tr>
    <th></th>
    ${featureNames.map(name => s"<th>$name</th>").mkString("")}
  </tr>
  ${(0 until corrMat.numRows).map { i =>
    s"""
    <tr>
      <td><strong>${featureNames(i)}</strong></td>
      ${(0 until corrMat.numCols).map(j => s"<td>${corrMat(i, j).formatted("%.4f")}</td>").mkString("")}
    </tr>
    """
  }.mkString("")}
</table>
"""

// 打印字符串后,在Zeppelin新建单元格用%html渲染
println(htmlTable)

运行上面的代码后,新建一个Zeppelin单元格输入%html ${htmlTable},就能看到格式化后的完整表格了。

方法三:调整Zeppelin的显示参数(临时救急)

如果只是临时想查看完整的宽表,可以调整z.show()的参数,关闭截断并设置最大显示列数:

// 关闭截断,设置显示所有列
corrWideDF.show(truncate = false, numRows = 100, vertical = false)

不过50列的话横向会很长,可能需要拖动滚动条,体验不如前两种方法好。

内容的提问来源于stack exchange,提问作者djWann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:07:51