Scala Dataframe窗口滞后函数开启条件
我有一个带有以下记录的数据框Scala Dataframe窗口滞后函数开启条件,scala,dataframe,spark-dataframe,lag,feature-extraction,Scala,Dataframe,Spark Dataframe,Lag,Feature Extraction,我有一个带有以下记录的数据框 id col1 time A 1 2017-12-23 09:00 A-1 1 2017-12-23 11:00 A-1 1 2017-12-23 10:00 A 2 2017-12-23 08:00 A 3 2017-12-23 07:00 A-2 4 2017-12-23 12:00 A-1 4 2017-12-23 12:00 B 1
id col1 time
A 1 2017-12-23 09:00
A-1 1 2017-12-23 11:00
A-1 1 2017-12-23 10:00
A 2 2017-12-23 08:00
A 3 2017-12-23 07:00
A-2 4 2017-12-23 12:00
A-1 4 2017-12-23 12:00
B 1 2017-12-23 09:00
B-1 1 2017-12-23 11:00
B-1 1 2017-12-23 10:00
B 2 2017-12-23 08:00
B 3 2017-12-23 07:00
B-2 4 2017-12-23 12:00
B-1 4 2017-12-23 12:00
我想从上面的数据框中获取滞后特征,但在“id”列上有一个条件。是否可以在不更改记录的情况下给出滞后特征的条件?。我像下面一样累了
val window = Window.partitionBy("id").orderBy("time")
val resultDF = DF.withColumn("col1_lag",lag(DF("col1"), 1).over(window))
上述代码将导致基于分组ID的滞后特征,我想把值与“--”是子的,并且它们需要父母滞后特征。例如:id为A-1的行(子行)需要在其前面显示一个(父行)的值
预期结果如下所示id col1 time col1_lag
A 3 2017-12-23 07:00 null
A 2 2017-12-23 08:00 3
A 1 2017-12-23 09:00 2
A-1 1 2017-12-23 10:00 1
A-1 1 2017-12-23 11:00 1
A-1 4 2017-12-23 12:00 1
A-2 4 2017-12-23 12:00 1
B 3 2017-12-23 07:00 null
B 2 2017-12-23 08:00 3
B 1 2017-12-23 09:00 2
B-1 1 2017-12-23 10:00 1
B-1 1 2017-12-23 11:00 1
B-1 4 2017-12-23 12:00 1
B-2 4 2017-12-23 12:00 1
如果我理解您的需求更正,那么实现您的要求需要很多步骤(因此成本相当高):
行id
(如果DF已经有一个,父id
,isChild
,以及通过父id在窗口分区上的滞后(col1)`
父id
和isChild
扩展DF,保留行id
和col1 lag
子行的col1 lag
列表(即isChild
==true),使所有元素与列表的第一个元素相同,通过UDF使用行id将其压缩,然后重新展开分组的DF
col1滞后的row id
将步骤1中的扩展DF与步骤3中的调整DF连接起来
val DF = Seq(
("A", 1, "2017-12-23 09:00"),
("A-1", 1, "2017-12-23 11:00"),
("A-1", 1, "2017-12-23 10:00"),
("A", 2, "2017-12-23 08:00"),
("A", 3, "2017-12-23 07:00"),
("A-2", 4, "2017-12-23 12:00"),
("A-1", 4, "2017-12-23 12:00"),
("B", 1, "2017-12-23 09:00"),
("B-1", 1, "2017-12-23 11:00"),
("B-1", 1, "2017-12-23 10:00"),
("B", 2, "2017-12-23 08:00"),
("B", 3, "2017-12-23 07:00"),
("B-2", 4, "2017-12-23 12:00"),
("B-1", 4, "2017-12-23 12:00")
).toDF("id", "col1", "time")
import org.apache.spark.sql.expressions.Window
val winPid = Window.partitionBy("pid").orderBy("id", "time")
// Step 1
val expandedDF = DF.
withColumn("row_id", monotonically_increasing_id).
withColumn("pid", substring($"id", 0, 1)).
withColumn("is_child", when($"pid" === $"id", false).otherwise(true)).
withColumn("col1_lag", lag($"col1", 1, 0).over(winPid)).
orderBy($"pid", $"id", $"time")
expandedDF.show
// +---+----+----------------+------+---+--------+--------+
// | id|col1| time|row_id|pid|is_child|col1_lag|
// +---+----+----------------+------+---+--------+--------+
// | A| 3|2017-12-23 07:00| 4| A| false| 0|
// | A| 2|2017-12-23 08:00| 3| A| false| 3|
// | A| 1|2017-12-23 09:00| 0| A| false| 2|
// |A-1| 1|2017-12-23 10:00| 2| A| true| 1|
// |A-1| 1|2017-12-23 11:00| 1| A| true| 1|
// |A-1| 4|2017-12-23 12:00| 6| A| true| 1|
// |A-2| 4|2017-12-23 12:00| 5| A| true| 4|
// | B| 3|2017-12-23 07:00| 11| B| false| 0|
// | B| 2|2017-12-23 08:00| 10| B| false| 3|
// | B| 1|2017-12-23 09:00| 7| B| false| 2|
// |B-1| 1|2017-12-23 10:00| 9| B| true| 1|
// |B-1| 1|2017-12-23 11:00| 8| B| true| 1|
// |B-1| 4|2017-12-23 12:00| 13| B| true| 1|
// |B-2| 4|2017-12-23 12:00| 12| B| true| 4|
// +---+----+----------------+------+---+--------+--------+
// Step 2
val groupedDF = expandedDF.groupBy("pid", "is_child").agg(
collect_list("row_id").as("row_id_list"),
collect_list("col1_lag").as("col1_lag_list")
).orderBy($"pid", $"is_child")
groupedDF.show
// +---+--------+--------------+-------------+
// |pid|is_child| row_id_list|col1_lag_list|
// +---+--------+--------------+-------------+
// | A| false| [4, 3, 0]| [0, 3, 2]|
// | A| true| [2, 1, 6, 5]| [1, 1, 1, 4]|
// | B| false| [11, 10, 7]| [0, 3, 2]|
// | B| true|[9, 8, 13, 12]| [1, 1, 1, 4]|
// +---+--------+--------------+-------------+
// Step 3
def adjustAndZip = udf(
(row: Seq[Long], lag: Seq[Int], isChild: Boolean) => {
val adjustedLag = if (isChild) Seq.fill[Int](lag.length)(lag.head) else lag
row zip adjustedLag
})
val adjustedDF = groupedDF.withColumn("temp",
explode(adjustAndZip($"row_id_list", $"col1_lag_list", $"is_child"))
).select(
$"temp._1".as("row_id"), $"temp._2".as("col1_lag_adjusted")
)
adjustedDF.show
// +------+-----------------+
// |row_id|col1_lag_adjusted|
// +------+-----------------+
// | 4| 0|
// | 3| 3|
// | 0| 2|
// | 2| 1|
// | 1| 1|
// | 6| 1|
// | 5| 1|
// | 11| 0|
// | 10| 3|
// | 7| 2|
// | 9| 1|
// | 8| 1|
// | 13| 1|
// | 12| 1|
// +------+-----------------+
// Step 4
val resultDF = expandedDF.join(adjustedDF, Seq("row_id")).select(
$"pid", $"id", $"col1", $"time", $"col1_lag_adjusted"
).orderBy($"pid", $"id", $"time")
resultDF.show
// +---+---+----+----------------+-----------------+
// |pid| id|col1| time|col1_lag_adjusted|
// +---+---+----+----------------+-----------------+
// | A| A| 3|2017-12-23 07:00| 0|
// | A| A| 2|2017-12-23 08:00| 3|
// | A| A| 1|2017-12-23 09:00| 2|
// | A|A-1| 1|2017-12-23 10:00| 1|
// | A|A-1| 1|2017-12-23 11:00| 1|
// | A|A-1| 4|2017-12-23 12:00| 1|
// | A|A-2| 4|2017-12-23 12:00| 1|
// | B| B| 3|2017-12-23 07:00| 0|
// | B| B| 2|2017-12-23 08:00| 3|
// | B| B| 1|2017-12-23 09:00| 2|
// | B|B-1| 1|2017-12-23 10:00| 1|
// | B|B-1| 1|2017-12-23 11:00| 1|
// | B|B-1| 4|2017-12-23 12:00| 1|
// | B|B-2| 4|2017-12-23 12:00| 1|
// +---+---+----+----------------+-----------------+
如果是有价值的,什么是昂贵的?