我有一个带有四个时间戳列(clock_in
,clock_out
,sign_in
和sign_out
)的pyspark数据帧。我需要第三列(duration
),这是两列之间的差异,但是我根据哪条规则采用的差异取决于列本身的值:
clock_in > clock_out
,则duration = clock_in - clock_out
sign_in > clock_out
,则为duration = sign_out - clock_out
clock_in > sign_in
,则为duration = clock_in - clock_out
duration = 0
我尝试定义UDF并将其应用如下:
from pyspark.sql import *
def calc_dur(clock_in, clock_out, sign_in, sign_out):
if clock_in > clock_out:
return clock_in - clock_out
elif sign_out > clock_out:
return sign_out - clock_out
elif sign_in < clock_in:
return clock_in - sign_in
else:
return 0
dur_udf = udf(calc_dur)
df2 = df.withColumn("duration", dur_udf(df.clock_in, df.clock_out, df.sign_in, df.sign_out))
但是,这会用Timedeltas(例如duration
)填充我的Timedelta: 0 days, 1740 seconds, 0 microseconds (total: 1740 seconds)
列,当我尝试过滤duration
列中的行时,其值仅是非零值返回零行。
正确的方法是什么?
答案 0 :(得分:1)
无需使用UDF(我认为它比较慢),您可以使用严格的Spark SQL语法来做到这一点:
列应该被强制转换为长列(如果它们是时间戳格式)。因此,您可以在每个F.col()之后添加这段代码:
F.col("...").cast(LongType())
链接到良好的SO答案:https://stackoverflow.com/a/37058395/6434448
然后我希望这段代码可以工作:
from pyspark.sql import functions as F
from pyspark.sql.types import LongType, TimestampType
df.withColumn("duration",
F.when(F.col("clock_in") > F.col("clock_out"), F.col("clock_in") - F.col("clock_out")).otherwise(
F.when(F.col("sign_out") > F.col("clock_out"), F.col("sign_out") - F.col("clock_out")).otherwise(
F.when(F.col("sign_in") < F.col("clock_in"), F.col("clock_in") - F.col("sign_in")).otherwise(F.lit(0))
))
)