2016-03-17 65 views
6

鉴于以下PySpark数据帧如何从Pyspark中的日期列中减去一列天数?

df = sqlContext.createDataFrame([('2015-01-15', 10), 
           ('2015-02-15', 5)], 
           ('date_col', 'days_col')) 

如何能在天塔从日期列减去?在这个例子中,结果列应该是['2015-01-05', '2015-02-10']

我看着pyspark.sql.functions.date_sub(),但它需要日期栏和一天,即date_sub(df['date_col'], 10)。理想情况下,我宁愿做date_sub(df['date_col'], df['days_col'])

我还试图建立一个UDF:

from datetime import timedelta 
def subtract_date(start_date, days_to_subtract): 
    return start_date - timedelta(days_to_subtract) 

subtract_date_udf = udf(subtract_date, DateType()) 
df.withColumn('subtracted_dates', subtract_date_udf(df['date_col'], df['days_col']) 

这种技术上的工作,但我看过的火花和Python之间步进可能会导致大型数据集的性能问题。我现在可以坚持使用这个解决方案(不需要过早优化),但是我的直觉说,只需要一种方法来做这个简单的事情而不使用Python UDF。

回答

3

我能用selectExpr解决这个问题。

df.selectExpr('date_sub(date_col, day_col) as subtracted_dates') 

如果要追加列到原来的DF,只需添加*来表达

df.selectExpr('*', 'date_sub(date_col, day_col) as subtracted_dates') 
+1

如果你不介意输入SQL,你实际上可以简化为'df.select(expr(“date_sub({0},{1})”)。format(“date_col”,“days_col”)))'这是微不足道的。 – zero323

1

不是最完美的解决方案永远,但如果你不想劈在斯卡拉SQL表达式(不,应该是困难的,但这些都是私有sql)这样的事情应该做的伎俩:

from pyspark.sql import Column 

def date_sub_(c1: Column, c2: Column) -> Column: 
    return ((c1.cast("timestamp").cast("long") - 60 * 60 * 24 * c2) 
     .cast("timestamp").cast("date")) 

对于Python 2.x只是放置类型注释。

+0

聪明。我想我使用'selectExpr'找到了一个稍微优雅的解决方案,但是感谢您的帮助! – kjmij

0

格式稍有不同,但也可以工作:

df.registerTempTable("dfTbl") 

newdf = spark.sql(""" 
        SELECT *, date_sub(d.date_col, d.day_col) AS DateSub 
        FROM dfTbl d 
        """) 
相关问题