Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何按行计算平均值?_Java_Apache Spark_Dataset_Apache Spark Sql - Fatal编程技术网

Java 如何按行计算平均值?

Java 如何按行计算平均值?,java,apache-spark,dataset,apache-spark-sql,Java,Apache Spark,Dataset,Apache Spark Sql,我试图思考如何平均多个列的值,并将其放入一个列中。然而,如果有一个空值,我想把它从平均计算中去掉。更具体地说,该表如下所示: +---------------+---------------+---------------+ | user| month_01| month_02| +---------------+---------------+---------------+ | garrison| 3.2|

我试图思考如何平均多个列的值,并将其放入一个列中。然而,如果有一个空值,我想把它从平均计算中去掉。更具体地说,该表如下所示:

+---------------+---------------+---------------+
|           user|       month_01|       month_02|
+---------------+---------------+---------------+
|       garrison|            3.2|            3.0|
|          marta|           null|            1.8|
|        garrett|            4.3|            7.8|
|         harold|            4.5|            3.1|
|          marta|            6.7|            7.2|
|           niko|            4.1|            5.8|
|          james|            9.5|           null|
|          manny|            1.9|            9.8|
|        charles|            7.8|            7.6| ...
+---------------+---------------+---------------+
+---------------+---------------+
|           user|        average|
+---------------+---------------+
|       garrison|           34.9|
|          marta|            2.3|
|        garrett|           4.43|
|         harold|            8.5|
|          marta|            6.0|
|           niko|            1.1|
|          james|            3.2|
|          manny|            0.7|
|        charles|            7.1|
+---------------+---------------+
我想对所有月份进行平均,得到一个最终的表,其中有两列,一列是用户,另一列是所有月份值的平均值。但是我不想让空值成为一个因素,所以如果用户行的所有月份都有一个空值,那么您只需要除以11。我正在努力思考如何使用Spark实现这一点。最终的表格将如下所示:

+---------------+---------------+---------------+
|           user|       month_01|       month_02|
+---------------+---------------+---------------+
|       garrison|            3.2|            3.0|
|          marta|           null|            1.8|
|        garrett|            4.3|            7.8|
|         harold|            4.5|            3.1|
|          marta|            6.7|            7.2|
|           niko|            4.1|            5.8|
|          james|            9.5|           null|
|          manny|            1.9|            9.8|
|        charles|            7.8|            7.6| ...
+---------------+---------------+---------------+
+---------------+---------------+
|           user|        average|
+---------------+---------------+
|       garrison|           34.9|
|          marta|            2.3|
|        garrett|           4.43|
|         harold|            8.5|
|          marta|            6.0|
|           niko|            1.1|
|          james|            3.2|
|          manny|            0.7|
|        charles|            7.1|
+---------------+---------------+
因此average列是每个用户行中所有值的平均值。

(我使用Scala作为编程语言,与所请求的相反,即Java)

解决方案1-映射运算符 我想到的一个解决办法是使用运算符

映射[U](函数:(T)⇒ U) (隐式arg0:Encoder[U]):数据集[U]返回一个新的数据集,其中包含对每个元素应用func的结果

因此,解决方案如下:

scala> months.show
+--------+--------+--------+
|    user|month_01|month_02|
+--------+--------+--------+
|garrison|     3.2|     3.0|
|   marta|    null|     1.8|
| garrett|     4.3|     7.8|
|  harold|     4.5|     3.1|
|   marta|     6.7|     7.2|
|    niko|     4.1|     5.8|
|   james|     9.5|    null|
|   manny|     1.9|     9.8|
| charles|     7.8|     7.6|
+--------+--------+--------+

val solution = months.map { r =>
  val skipUserColumn = 1
  // be generic as much as possible
  // the number of months can be any number
  val monthsCount = r.size - skipUserColumn
  val nullCount = (skipUserColumn until r.size).count(r.isNullAt)
  val sum = (skipUserColumn until r.size).
    foldLeft(0.0) { 
      case (sum, idx) if !r.isNullAt(idx) => sum + r.getDouble(idx)
      case (sum, idx) => sum
    }
  (r.getString(0), sum / (monthsCount - nullCount))
}.toDF("user", "month_avg")
scala> solution.show
+--------+------------------+
|    user|         month_avg|
+--------+------------------+
|garrison|               3.1|
|   marta|               1.8|
| garrett|              6.05|
|  harold|               3.8|
|   marta|              6.95|
|    niko| 4.949999999999999|
|   james|               9.5|
|   manny|5.8500000000000005|
| charles| 7.699999999999999|
+--------+------------------+
解决方案2-带函数的withColumn运算符 我认为使用
map
操作符与基于UDF的操作符一样无效。它们都在JVM上加载二进制行,因此内存需求高于避免复制(从内部二进制行格式复制到JVM对象)的解决方案

我认为
withColumn
运算符和
函数
对象的执行成本可以提供更好的性能(并且更容易理解)

然而,数据集存在一个问题,即
user
列不是唯一的,因此不可能使用聚合

如果第5行中的另一个
marta
被排除在外,我会用我心爱的窗口聚合提出以下解决方案

// Remember user column is now assumed unique
// I'm however not excluding it from calculation
// just assume that (user, month_01) would be unique
// user and all months together could get us closer to the requirement
import org.apache.spark.sql.expressions.Window
val userAndMonth01 = Window.partitionBy("user", "month_01")
val solution = partial_solution.
  withColumn("avg", avg("exploded") over userAndMonth01).
  select("user", "avg").
  distinct  // <-- be careful since we might get non-unique pairs of user and avg
scala> solution.show
+--------+------------------+
|    user|               avg|
+--------+------------------+
|  harold|               3.8|
|garrison|               3.1|
| garrett|              6.05|
|   manny|5.8500000000000005|
| charles| 7.699999999999999|
|    niko| 4.949999999999999|
|   marta|              6.95|
|   james|               9.5|
|   marta|               1.8|
+--------+------------------+
//记住用户列现在假定是唯一的
//然而,我并没有把它排除在计算之外
//只需假设(用户,月\ 01)是唯一的
//用户和所有的月份加在一起可以使我们更接近要求
导入org.apache.spark.sql.expressions.Window
val userAndMonth01=Window.partitionBy(“用户”、“月份”)
val溶液=部分溶液。
在userAndMonth01上的列(“平均值”,平均值(“分解”)。
选择(“用户”、“平均值”)。
distinct//solution.show
+--------+------------------+
|用户平均值|
+--------+------------------+
|哈罗德| 3.8|
|驻军| 3.1|
|加勒特| 6.05|
|曼尼| 5.850000000000005|
|查尔斯| 7.69999999|
|尼科| 4.94999999|
|玛尔塔6.95|
|詹姆斯| 9.5|
|玛尔塔1.8|
+--------+------------------+
(我使用Scala作为编程语言,与请求相反,即Java)

解决方案1-映射运算符 我想到的一个解决办法是使用运算符

映射[U](函数:(T)⇒ U) (隐式arg0:Encoder[U]):数据集[U]返回一个新的数据集,其中包含对每个元素应用func的结果

因此,解决方案如下:

scala> months.show
+--------+--------+--------+
|    user|month_01|month_02|
+--------+--------+--------+
|garrison|     3.2|     3.0|
|   marta|    null|     1.8|
| garrett|     4.3|     7.8|
|  harold|     4.5|     3.1|
|   marta|     6.7|     7.2|
|    niko|     4.1|     5.8|
|   james|     9.5|    null|
|   manny|     1.9|     9.8|
| charles|     7.8|     7.6|
+--------+--------+--------+

val solution = months.map { r =>
  val skipUserColumn = 1
  // be generic as much as possible
  // the number of months can be any number
  val monthsCount = r.size - skipUserColumn
  val nullCount = (skipUserColumn until r.size).count(r.isNullAt)
  val sum = (skipUserColumn until r.size).
    foldLeft(0.0) { 
      case (sum, idx) if !r.isNullAt(idx) => sum + r.getDouble(idx)
      case (sum, idx) => sum
    }
  (r.getString(0), sum / (monthsCount - nullCount))
}.toDF("user", "month_avg")
scala> solution.show
+--------+------------------+
|    user|         month_avg|
+--------+------------------+
|garrison|               3.1|
|   marta|               1.8|
| garrett|              6.05|
|  harold|               3.8|
|   marta|              6.95|
|    niko| 4.949999999999999|
|   james|               9.5|
|   manny|5.8500000000000005|
| charles| 7.699999999999999|
+--------+------------------+
解决方案2-带函数的withColumn运算符 我认为使用
map
操作符与基于UDF的操作符一样无效。它们都在JVM上加载二进制行,因此内存需求高于避免复制(从内部二进制行格式复制到JVM对象)的解决方案

我认为
withColumn
运算符和
函数
对象的执行成本可以提供更好的性能(并且更容易理解)

然而,数据集存在一个问题,即
user
列不是唯一的,因此不可能使用聚合

如果第5行中的另一个
marta
被排除在外,我会用我心爱的窗口聚合提出以下解决方案

// Remember user column is now assumed unique
// I'm however not excluding it from calculation
// just assume that (user, month_01) would be unique
// user and all months together could get us closer to the requirement
import org.apache.spark.sql.expressions.Window
val userAndMonth01 = Window.partitionBy("user", "month_01")
val solution = partial_solution.
  withColumn("avg", avg("exploded") over userAndMonth01).
  select("user", "avg").
  distinct  // <-- be careful since we might get non-unique pairs of user and avg
scala> solution.show
+--------+------------------+
|    user|               avg|
+--------+------------------+
|  harold|               3.8|
|garrison|               3.1|
| garrett|              6.05|
|   manny|5.8500000000000005|
| charles| 7.699999999999999|
|    niko| 4.949999999999999|
|   marta|              6.95|
|   james|               9.5|
|   marta|               1.8|
+--------+------------------+
//记住用户列现在假定是唯一的
//然而,我并没有把它排除在计算之外
//只需假设(用户,月\ 01)是唯一的
//用户和所有的月份加在一起可以使我们更接近要求
导入org.apache.spark.sql.expressions.Window
val userAndMonth01=Window.partitionBy(“用户”、“月份”)
val溶液=部分溶液。
在userAndMonth01上的列(“平均值”,平均值(“分解”)。
选择(“用户”、“平均值”)。
distinct//solution.show
+--------+------------------+
|用户平均值|
+--------+------------------+
|哈罗德| 3.8|
|驻军| 3.1|
|加勒特| 6.05|
|曼尼| 5.850000000000005|
|查尔斯| 7.69999999|
|尼科| 4.94999999|
|玛尔塔6.95|
|詹姆斯| 9.5|
|玛尔塔1.8|
+--------+------------------+