我有一个数据框dataDF
,即:
+-------+------+-----+-----+-----------+
|TEST_PK| COL_1|COL_2|COL_3|h_timestamp|
+-------+------+-----+-----+-----------+
| 1| apple| 10| 1.79| 1111|
| 1| apple| 11| 1.79| 1114|
| 2|banana| 15| 1.79| 1112|
| 2|banana| 16| 1.79| 1115|
| 3|orange| 7| 1.79| 1113|
+-------+------+-----+-----+-----------+
我需要运行此功能:
operation(row, h_timestamp)
在每一行上,但是row
不能包含h_timestamp
,所以我的第一个想法是像这样拆分数据帧:
val columns = dataDF.drop("h_timestamp")
val timestamp = dataDF.select("h_timestamp")
但是当我想对每一行执行该操作时,这没有帮助:
dataDF.map(row => {
...
val rowWithoutTimestamp = ???
val timestamp = ???
operation(rowWithoutTimestamp, timestamp)
...
})
但是现在这两个数据帧没有链接,我不知道如何为每一行获取正确的时间戳。 TEST_PK
列不一定是唯一的。
有没有一种方法可以仅在一行上使用.drop()
或.select()
或其他某种方式?
编辑:此外,该表可以具有任意数量的列,但始终具有时间戳列,并且至少还有一个不是时间戳的列
答案 0 :(得分:0)
由于您似乎有一个主键列,因此只需将带有id列的时间戳插入其自己的数据框中,以便稍后重新加入。
val tsDF = dataDF.select("TEST_PK", "h_timestamp")
然后,将列从dataDF
中删除,进行操作,然后将h_timestamp重新加入新的数据框中。
val finalDF = postopDF.join(tsDF, "TEST_PK")
更新
示例代码很有帮助,您应该基本上可以分解行,并使用类似以下内容的值重建新行:
dataDF.map(row => {
val rowWithoutTimestamp = Row(
row.getAs[Long]("TEST_PK"),
row.getAs[String]("COL_1"),
row.getAs[Long]("COL_2"),
row.getAs[Double]("COL_3")
)
val timestamp = row.getAs[Long]("h_timestamp")
val result = operation(rowWithoutTimestamp, timestamp)
Row(result, timestamp)
})
当然,我不确定您的operation()
返回什么,因此可能有必要将result
分解为单个值,并用这些值和时间戳组成新行。
更新2
好的,这是一个更通用的方法。它将“ h_timestamp
以外的所有列”包装到一个结构中,并映射到(struct, ts)
元组上。其实比以前的解决方案还优雅。
val cols = df.drop("h_timestamp").columns.toSeq
dataDF
.select(struct(cols.map(c => col(c)):_*).as("row_no_ts"), $"h_timestamp")
.map(row => {
val rowWithoutTimestamp = row.getAs[Row]("row_no_ts")
val timestamp = row.getAs[Long]("h_timestamp")
operation(rowWithoutTimestamp, timestamp)
})
我不确定您是要映射到operation()
的输出还是再次与时间戳进行某种组合,但是两者都可以根据需要进行修改。