web-dev-qa-db-ja.com

Pysparkの日付の列から日付の列を引く方法は?

次のPySpark DataFrameがあるとします。

_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()を調べましたが、日付列と1日が必要です(つまり、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'])
_

これは技術的には機能しますが、SparkとPythonの間でステッピングすると、大規模なデータセットでパフォーマンスの問題が発生する可能性があることを読みました。今のところこの解決策を続けることができます(時期尚早に最適化する必要はありません)が、私の直感はPython UDFを使用せずにこの単純なことを行う方法があるはずだと言っています。

13
kjmij

selectExprを使用してこれを解決することができました。

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

列を元のDFに追加する場合は、式に*を追加するだけです

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

expr関数を使用します(dynamic values列から差し引くまで):

>>> from pyspark.sql.functions import *
>>> df.withColumn('substracted_dates',expr("date_sub(date_col,days_col)"))

withColumn function(-literal values減算する):

>>> df.withColumn('substracted_dates',date_sub('date_col',<int_literal_value>))
3
Shu

これまでで最もエレガントな解決策ではありませんが、Scalaで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の場合は、型注釈をドロップするだけです。

1
zero323

わずかに異なる形式ですが、動作もします。

df.registerTempTable("dfTbl")

newdf = spark.sql("""
                     SELECT *, date_sub(d.date_col, d.day_col) AS DateSub 
                     FROM dfTbl d
                   """)
0
Grant Shannon