2016-03-17 95 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 
        """) 
相關問題