使用scala数据帧中的最小值和最大值查找正常值

使用scala数据帧中的最小值和最大值查找正常值,scala,dataset,spark-dataframe,user-defined-functions,unsupervised-learning,Scala,Dataset,Spark Dataframe,User Defined Functions,Unsupervised Learning,我有一个数据框,有39列,每列有不同的正常范围。 通过使用正常范围,我想找出正常值,然后把0放到1 这是我做的,但我想为39专栏做的 val test :(Double => Double) = (value: Double) => { if(value >= 45 && value <= 62) 0 else 1 } 我想要的结果如下使用范围 col range a 50-160 b 1-21 c 5-40 d 7-

我有一个数据框,有39列,每列有不同的正常范围。 通过使用正常范围,我想找出正常值,然后把0放到1

这是我做的,但我想为39专栏做的

val test :(Double => Double) =  (value: Double) =>
{
    if(value >= 45 && value <= 62) 0
    else 1
}
我想要的结果如下使用范围

col  range
a   50-160
b   1-21
c   5-40
d   7-27
如果值在范围内,则为0,否则为1

+--------------------+---------+-------------------------+---------+
|a                   |b        |c                        |d        |
+--------------------+---------+-------------------------+---------+
|                 1.0|      1.0|                      1.0|      1.0|
|                 0.0|      0.0|                      1.0|      0.0|
|                 1.0|      0.0|                      1.0|      0.0|
|                 1.0|      1.0|                      1.0|      0.0|
|                 1.0|      1.0|                      1.0|      0.0|
|                 1.0|      1.0|                      1.0|      1.0|
|                 1.0|      1.0|                      1.0|      1.0|
|                 1.0|      1.0|                      1.0|      0.0|
|                 1.0|      1.0|                      1.0|      0.0|
|                 1.0|      1.0|                      1.0|      1.0|

I want to do this for 39 columns.(scala/pyspark preferred)

您应该定义一个用户定义函数(UDF),然后将其应用于您想要的每一列

下面是有关Scala用户定义函数的文档。它相当完整,我鼓励你阅读它

这里有一个摘录,可以帮助您快速理解我想去的地方:

scala> df.withColumn("upper", upper('text)).show
+---+-----+-----+
| id| text|upper|
+---+-----+-----+
|  0|hello|HELLO|
|  1|world|WORLD|
+---+-----+-----+

// You could have also defined the UDF this way
val upperUDF = udf { s: String => s.toUpperCase }

// or even this way
val upperUDF = udf[String, String](_.toUpperCase)

scala> df.withColumn("upper", upperUDF('text)).show
+---+-----+-----+
| id| text|upper|
+---+-----+-----+
|  0|hello|HELLO|
|  1|world|WORLD|
+---+-----+-----+
您可以看到,您的函数应用于整个列,结果将是一个新列。因此,您的函数应该如下所示:

def isInRange(e: Number, min: Number, max: Number): Boolean = (e < max && e > min)
resultDF.drop(rangesList.map(case x => x._0).collect: _*)
现在,您可以在包含(varName、maxValue、minValue)的给定列表/数据帧上应用它:

  • 或者是一个map/reduce操作,您可以为每一列计算它是否在给定的范围内。然后,你将加入一个给定的密钥(我不知道你的问题,所以我不能在这里帮助你)。这个解决方案可以工作,但随着数据的增长,效率会变得非常低下,因为您可能会有几个看起来相似的键

  • 要么是递归操作,目标是执行类似以下操作:
    myDF.whithColumn(…).withColumn(…).withColumn(…)

第二个解决方案是我将选择的一个,因为键可能看起来很像

你是怎么做到的

def applyMyUDFRecursively(myDF: DataFrame, List[MyRange]: rangesList): DataFrame =
if (rangesList == null || rangesList.isEmpty) myDF
else applyMyUDFRecursively(
    myDF.withColumn(myDF.withColumn("isInRange_" + rangesList.head._0, udf(x => isInRange(x, rangesList.head._1, rangesList.head._2).apply(myDF(rangesList.head._0))), rangesList.tail)
现在已应用于所有列,但可能列太多。这样做:

def isInRange(e: Number, min: Number, max: Number): Boolean = (e < max && e > min)
resultDF.drop(rangesList.map(case x => x._0).collect: _*)
请注意类型归属,将drop函数应用于map/collect时获得的列表中的所有元素

val MyRange=Seq(varName:String,min:Number,max:Number)

例如,对于您的数据帧,它应该如下所示(更简单的版本):

然后,将此函数应用于DF并存储结果:

val my_result = recApply(myDF, myDF.cols)

如果有不清楚的地方请告诉我,我希望我给了你钥匙,让你现在自己处理这个问题,不要犹豫,把这个问题标记为已回答如果这适合你,我很感激你的回答这是我得到的最详细的答案,但仍然没有处理所有39列。你能只显示上面的样本数据吗?它也会更有用,你可以在上面看到我的自定义项你的自定义项在哪里?
val my_result = recApply(myDF, myDF.cols)