我有一个包含10个字段和5000行的数据集。我想用Spark with Scala中的一些统计方法来完成这个数据集。我填充了一个字段的空单元格,其中包含该字段的平均值,如果它由连续值组成,并且我将最常用的值放在字段中,如果它由离散值组成。这是我的代码:
for(col <- cols){
val datacount = table.select(col).rdd.map(r => r(0)).filter(_ == null).count()
if(datacount > 0)
{
if (continuous_lst contains col) // put mean of data to null values
{
var avg = table.select(mean(col)).first()(0).asInstanceOf[Double]
df = df.na.fill(avg, Seq(col))
}
else if(discrete_lst contains col) // put most frequent categorical value to null values
{
val group_df = df.groupBy(col).count()
val sorted = group_df.orderBy(desc("count")).take(1)
val most_frequent = sorted.map(t => t(0))
val most_frequent_ = most_frequent(0).toString.toDouble.toInt
val type__ = ctype.filter(t => t._1 == col)
val type_ = type__.map(t => t._2)
df = df.na.fill(most_frequent_, Seq(col))
}
}
}
问题是此代码对此数据的运行速度非常慢。我将spark-submit
与executor memory 8G
参数一起使用。在将数据发送到此函数之前,我使用repartition(4)参数。
我应该使用更大尺寸的数据集。那么我怎样才能加快这段代码的速度呢?
感谢您的帮助。
答案 0 :(得分:2)
这是一个建议:
import org.apache.spark.sql.funcitons._
def most_frequent(df: DataFrame, col: Column) = {
df.select(col).map { case Row(colVal) => (colVal, 1) }
.reduceByKey(_ + _)
.reduce({case ((val1, cnt1), (val2, cnt2)) => if (cnt1 > cnt2) (val1, cnt1) else (val2, cnt2)})._1
}
val new_continuous_cols = continuous_lst.map {
col => coalesce(col, mean(col)).as(col.toString)
}.toArray
val new_discrete_cols = discrete_lst.map {
col => coalesce(col, lit(most_frequent(table, col)).as(col.toString))
}.toArray
val all_new_cols = new_continuous_cols ++ new_discrete_cols
val newDF = table.select(all_new_cols: _*)
<强>考虑:强>
continuous_lst
和discrete_lst
是Column
的列表。如果它们是String
的列表,那么这个想法是相同的,但有些调整是必要的; map
和reduce
来计算列的最常用值。在某些情况下,这可能比分组和聚合更好。 (也许这里有改进的余地,一次计算所有离散列的最常见值?); coalesce
替换空值,而不是fill
。这也可能导致一些改进。 (有关scaladoc API)中coalesce
功能的更多信息;