2016-04-07 79 views
3

我有以下格式的數據幀設置一個列值:SPARK:基於多行條件

+----+---+-----+------+-----+------+ 
|AGEF|SEX|F0_34|F35_44|M0_34|M35_44| 
+----+---+-----+------+-----+------+ 
| 30| 0| 0|  0| 0|  0| 
| 94| 1| 0|  0| 0|  0| 
| 94| 0| 0|  0| 0|  0| 
| 94| 0| 0|  0| 0|  0| 
| 94| 1| 0|  0| 0|  0| 
| 44| 0| 0|  0| 0|  0| 
| 66| 0| 0|  0| 0|  0| 
| 66| 0| 0|  0| 0|  0| 
| 74| 0| 0|  0| 0|  0| 
| 74| 0| 0|  0| 0|  0| 
| 29| 0| 0|  0| 0|  0| 

現在基於列AGEF我需要分配1到相應的列名的價值觀和性別。每個欄目名稱都是自我解釋性的,就像F0_34在0到34歲之間的女性一樣,對於其他情況也是如此。

預期成果是提前

+----+---+-----+------+-----+------+ 
|AGEF|SEX|F0_34|F35_44|M0_34|M35_44| 
+----+---+-----+------+-----+------+ 
| 30| 0| 1|  0| 0|  0| 
| 94| 1| 0|  0| 0|  0| 
| 94| 0| 0|  0| 0|  0| 
| 94| 0| 0|  0| 0|  0| 
| 94| 1| 0|  0| 0|  0| 
| 44| 0| 0|  1| 0|  0| 
| 66| 0| 0|  0| 0|  0| 
| 66| 0| 0|  0| 0|  0| 
| 74| 0| 0|  0| 0|  0| 
| 74| 0| 0|  0| 0|  0| 
| 29| 0| 1|  0| 0|  0| 

謝謝!

回答

4

通常最有效的方法是直接對SQL表達式進行操作。例如:

def categorize(ageRanges: Seq[(Int, Int)], sexValues: Seq[(Int, String)]) = for { 
    (ageL, ageH) <- ageRanges 
    (sexV, sexL) <- sexValues 
} yield ($"SEX" === sexL && $"AGEF".between(ageL, ageH)).alias(
    s"$sexL-$ageL-$ageH" 
) 

df.select(
    $"*" +: categorize(Seq((0, 34), (35, 44)), Seq((0, "F"), (1, "M"))): _* 
) 
3

簡單的方法就是做一個UDF是需要5個參數(例如:actual_age,actual_sex,target_sex,target_min_age,target_max_age),返回1或0。事情是這樣的:如果你有

val ageRanger = udf[Int,Int,Int,Int,Int,Int]((age: Int, sex: Int, targetSex: Int, targetMinAge: Int, targetMaxAge: Int) => { 
    if (age >= targetMinAge && age <= targetMaxAge && sex == targetSex) 1 else 0 
}) 

然後這DataFrame

val df = Seq((30,0),(94,1),(94,0),(44,0)).toDF("AGEF", "SEX") 
// +----+---+ 
// |AGEF|SEX| 
// +----+---+ 
// | 30| 0| 
// | 94| 1| 
// | 94| 0| 
// | 44| 0| 
// +----+---+ 

df.withColumn("F0_34", ageRanger($"AGEF", $"SEX", lit(0), lit(0), lit(34))) 
    .withColumn("F35_44", ageRanger($"AGEF", $"SEX", lit(0), lit(35), lit(44))) 
    .show 
// +----+---+-----+------+ 
// |AGEF|SEX|F0_34|F35_44| 
// +----+---+-----+------+ 
// | 30| 0| 1|  0| 
// | 94| 1| 0|  0| 
// | 94| 0| 0|  0| 
// | 44| 0| 0|  1| 
// +----+---+-----+------+ 

注意,您必須將值傳遞到UDFColumns,所以我用lit(...)來包裝我Int值的硬編碼值。可以有一個很好的方式來做到這一點,但它可以很好地工作。