2016-06-28 55 views
19

Ho un data dataframe pyspark con una colonna di stringhe nel formato MM-dd-yyyy e sto tentando di convertirlo in una colonna di date.Converti stringa pyspark in formato data

ho provato:

df.select(to_date(df.STRING_COLUMN).alias('new_date')).show()

e ottengo una serie di valori nulli. Qualcuno può aiutare?

+0

A meno che non si sta utilizzando uno dei addons TimeSeriesRDD (vedi la conferenza Spark 2016 per qualche discussione, ci sono due che conosco, ma entrambi sono ancora in fase di sviluppo), non ci non sono molti ottimi strumenti per le serie temporali. Di conseguenza, ho scoperto che raramente c'è un motivo per disturbare la conversione di stringhe in oggetti datetime, se il tuo obiettivo è un verosimile tipo di operazioni di "groupBy" o ricampionamento. Eseguili semplicemente sulle colonne degli archi. – Jeff

+0

L'analisi sarà fatta usando poco o nulla '' 'groupBy''' ma piuttosto studi longitudinali di cartelle cliniche. Quindi essere in grado di manipolare la data è importante – Jenks

+0

Possibile duplicato di [Perché ottengo risultati nulli dalla data \ _format() funzione PySpark?] (Http://stackoverflow.com/questions/36094413/why-i-get-null- result-from-date-format-pyspark-function) –

risposta

21

E 'possibile fare questo senza un UDF (preferibile?):

> from pyspark.sql.functions import unix_timestamp 

> df = spark.createDataFrame([("11/25/1991",), ("11/24/1991",), ("11/30/1991",)], ['date_str']) 

> df2 = df.select('date_str', from_unixtime(unix_timestamp('date_str', 'MM/dd/yyy')).alias('date')) 

> df2 

DataFrame[date_str: string, date: timestamp] 

> df2.show() 

+----------+--------------------+ 
| date_str|    date| 
+----------+--------------------+ 
|11/25/1991|1991-11-25 00:00:...| 
|11/24/1991|1991-11-24 00:00:...| 
|11/30/1991|1991-11-30 00:00:...| 
+----------+--------------------+ 

Aggiornamento (2018/01/10) :

Il modo migliore per eseguire questa operazione è probabilmente l'uso di to_date o to_timestamp, che supportano entrambi l'argomento format. Dai documenti:

>>> df = spark.createDataFrame([('1997-02-28 10:30:00',)], ['t']) 
>>> df.select(to_timestamp(df.t, 'yyyy-MM-dd HH:mm:ss').alias('dt')).collect() 
[Row(dt=datetime.datetime(1997, 2, 28, 10, 30))] 
+1

Questa è la risposta corretta. Usando un udf per questo distruggerà la tua performance. – gberger

+0

da pyspark.sql.functions import from_unixtime, unix_timestamp – Quetzalcoatl

+0

Si noti che è possibile trovare un riferimento al formato data java qui: https://docs.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html – RobinL

27
from datetime import datetime 
from pyspark.sql.functions import col, udf 
from pyspark.sql.types import DateType 



# Creation of a dummy dataframe: 
df1 = sqlContext.createDataFrame([("11/25/1991","11/24/1991","11/30/1991"), 
          ("11/25/1391","11/24/1992","11/30/1992")], schema=['first', 'second', 'third']) 

# Setting an user define function: 
# This function converts the string cell into a date: 
func = udf (lambda x: datetime.strptime(x, '%m/%d/%Y'), DateType()) 

df = df1.withColumn('test', func(col('first'))) 

df.show() 

df.printSchema() 

Ecco l'output:

+----------+----------+----------+----------+ 
|  first| second|  third|  test| 
+----------+----------+----------+----------+ 
|11/25/1991|11/24/1991|11/30/1991|1991-01-25| 
|11/25/1391|11/24/1992|11/30/1992|1391-01-17| 
+----------+----------+----------+----------+ 

root 
|-- first: string (nullable = true) 
|-- second: string (nullable = true) 
|-- third: string (nullable = true) 
|-- test: date (nullable = true) 
+5

Un 'udf' non dovrebbe essere necessario qui, ma i built-in per la gestione di questo sono atroci. Questo è quello che farei anche per ora. – Jeff

+3

Perché le date non corrispondono nella colonna di test alla prima colonna? Sì, ora è di tipo data, ma i giorni e i mesi non corrispondono. C'è una ragione? Il test – Jenks

+1

fornisce valori errati per la data. Questa non è la risposta giusta. – Shehryar

6

L'approccio strptime() non funziona per me. Ottengo un'altra soluzione più pulita, usando Cast:

from pyspark.sql.types import DateType 
spark_df1 = spark_df.withColumn("record_date",spark_df['order_submitted_date'].cast(DateType())) 
#below is the result 
spark_df1.select('order_submitted_date','record_date').show(10,False) 

+---------------------+-----------+ 
|order_submitted_date |record_date| 
+---------------------+-----------+ 
|2015-08-19 12:54:16.0|2015-08-19 | 
|2016-04-14 13:55:50.0|2016-04-14 | 
|2013-10-11 18:23:36.0|2013-10-11 | 
|2015-08-19 20:18:55.0|2015-08-19 | 
|2015-08-20 12:07:40.0|2015-08-20 | 
|2013-10-11 21:24:12.0|2013-10-11 | 
|2013-10-11 23:29:28.0|2013-10-11 | 
|2015-08-20 16:59:35.0|2015-08-20 | 
|2015-08-20 17:32:03.0|2015-08-20 | 
|2016-04-13 16:56:21.0|2016-04-13 | 
+3

Grazie, questo approccio ha funzionato per me! Nel caso in cui qualcuno voglia convertire una stringa come '2008-08-01T14: 45: 37Z' in un timestamp invece di una data,' df = df.withColumn ("CreationDate", df ['CreationDate']. Cast (TimestampType ())) 'funziona bene ... (Spark 2.2.0) – Gaurav

+0

Siete i benvenuti, e grazie per aver votato per il mio post! – Frank