次の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を使用せずにこの単純なことを行う方法があるはずだと言っています。
selectExpr
を使用してこれを解決することができました。
df.selectExpr('date_sub(date_col, day_col) as subtracted_dates')
列を元のDFに追加する場合は、式に*
を追加するだけです
df.selectExpr('*', 'date_sub(date_col, day_col) as subtracted_dates')
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>))
これまでで最もエレガントな解決策ではありませんが、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の場合は、型注釈をドロップするだけです。
わずかに異なる形式ですが、動作もします。
df.registerTempTable("dfTbl")
newdf = spark.sql("""
SELECT *, date_sub(d.date_col, d.day_col) AS DateSub
FROM dfTbl d
""")