Python 如何将一列添加到Spark数据框中,其中每个新元素都依赖于另一列的groupby?
我有一个Spark数据框,格式如下:Python 如何将一列添加到Spark数据框中,其中每个新元素都依赖于另一列的groupby?,python,apache-spark,dataframe,pyspark,apache-spark-sql,Python,Apache Spark,Dataframe,Pyspark,Apache Spark Sql,我有一个Spark数据框,格式如下: +----------+-----+-------+-------+ |时间戳| lat | lon |用户id| +----------+-----+-------+-------+ |1511512345|34.12|-120.12| 1| |1511512348|34.13|-120.13| 1| |1511512349|34.14|-120.14| 1| |1511551234|31.11|-122.01| 2
+----------+-----+-------+-------+
|时间戳| lat | lon |用户id|
+----------+-----+-------+-------+
|1511512345|34.12|-120.12| 1|
|1511512348|34.13|-120.13| 1|
|1511512349|34.14|-120.14| 1|
|1511551234|31.11|-122.01| 2|
|1511551236|31.15|-122.03| 2|
+----------+-----+-------+-------+
我需要对每个用户的位置数据的时间序列进行计算。计算需要具有用于地图匹配的lat/lon数据的整个时间序列(即,找到GPS位置到道路地图的最佳映射)。结果是一系列的road\u id
s,然后我想将它们附加到数据帧中
+----------+-----+-------+-------+-------+
|时间戳| lat | lon |用户id |道路id|
+----------+-----+-------+-------+-------+
|1511512345|34.12|-120.12| 1| 12|
|1511512348|34.13|-120.13| 1| 12|
|1511512349|34.14|-120.14| 1| 345|
|1511551234|31.11|-122.01| 2| 737|
|1511551236|31.15|-122.03| 2| 643|
+----------+-----+-------+-------+-------+
请注意,为了执行此计算,我需要每个用户id
的整个时间序列(即计算不能逐行进行,但需要每个用户id
的整个组)如何使用spark dataframe API完成?我不确定是否可以使用groupby
和withColumn
或其他方法来实现这一点
df.sortby('timestamp').groupby('user_id').agg(...) ?
道路id
序列通常使用HMM模型计算,是道路网络和整个lat/lon序列的函数(如中所述)
基本上,地图匹配器的输入将是整个lat/lon值序列,输出将是相同长度的road_id值序列。您需要进行分组以生成新的数据帧,然后将此新数据帧与原始数据帧合并。您需要进行分组以生成新的数据帧,然后将这个新的数据帧与原来的数据帧连接起来。我使用Scala(因此给它加上标签的是YMMV)
我的理解是,您希望为数据集中每个
用户id
和整个lat
/lon
序列的每个记录计算一个值
在我看来,这是一个窗口聚合问题
让我们定义一个窗口规范(我再次使用Scala-so-YMMV)
我使用Scala(所以YMMV给它加了标签)
我的理解是,您希望为数据集中每个
用户id
和整个lat
/lon
序列的每个记录计算一个值
在我看来,这是一个窗口聚合问题
让我们定义一个窗口规范(我再次使用Scala-so-YMMV)
val input = Seq(
("1511512345", 34.12, -120.12, 1))
.toDF("timestamp", "lat", "lon", "user_id")
import org.apache.spark.sql.expressions.Window
val byUserId = Window.partitionBy("user_id").orderBy("timestamp")
val inputWithLatsAndLonsCols = input
.withColumn("lats", collect_list("lat") over byUserId)
.withColumn("lons", collect_list("lon") over byUserId)
scala> inputWithLatsAndLonsCols.show
+----------+-----+-------+-------+-------+---------+
| timestamp| lat| lon|user_id| lats| lons|
+----------+-----+-------+-------+-------+---------+
|1511512345|34.12|-120.12| 1|[34.12]|[-120.12]|
+----------+-----+-------+-------+-------+---------+
// define UDF to do the calculation
// NOTE that the UDF always returns 1 for demo purposes
val roadId = udf { (lats: Seq[Double], lons: Seq[Double]) => 1 }
val roads = inputWithLatsAndLonsCols.withColumn("road_id", roadId($"lats", $"lons"))
scala> roads.show
+----------+-----+-------+-------+-------+---------+-------+
| timestamp| lat| lon|user_id| lats| lons|road_id|
+----------+-----+-------+-------+-------+---------+-------+
|1511512345|34.12|-120.12| 1|[34.12]|[-120.12]| 1|
+----------+-----+-------+-------+-------+---------+-------+