Convertir cadena pyspark a formato de fecha

80

Tengo un marco de datos pyspark de fecha con una columna de cadena en el formato de MM-dd-yyyyy estoy intentando convertir esto en una columna de fecha.

Lo intenté:

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

y obtengo una cadena de nulos. ¿Alguien puede ayudar?

Jenks
fuente
A menos que esté utilizando uno de los complementos TimeSeriesRDD (consulte la conferencia Spark 2016 para una discusión, hay dos que conozco, pero ambos todavía están en desarrollo), no hay muchas herramientas excelentes para series temporales. En consecuencia, descubrí que rara vez hay una razón para molestarse en convertir cadenas en objetos de fecha y hora, si su objetivo son varios tipos de groupByoperaciones de remuestreo. Simplemente realícelos en las columnas de la cadena.
Jeff
El análisis se realizará utilizando pocos o ningún estudio, groupBysino más bien longitudinales, de los registros médicos. Por lo tanto, es importante poder manipular la fecha
Jenks

Respuestas:

114

Actualización (10/1/2018):

Para Spark 2.2+, la mejor manera de hacer esto probablemente sea usando las funciones to_dateo to_timestamp, que son compatibles con el formatargumento. De los documentos:

>>> from pyspark.sql.functions import to_timestamp
>>> 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))]

Respuesta original (para Spark <2.2)

Es posible (¿preferible?) Hacer esto sin un udf:

from pyspark.sql.functions import unix_timestamp, from_unixtime

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')
)

print(df2)
#DataFrame[date_str: string, date: timestamp]

df2.show(truncate=False)
#+----------+-------------------+
#|date_str  |date               |
#+----------+-------------------+
#|11/25/1991|1991-11-25 00:00:00|
#|11/24/1991|1991-11-24 00:00:00|
#|11/30/1991|1991-11-30 00:00:00|
#+----------+-------------------+
santon
fuente
3
Esta es la respuesta correcta. Usar un udf para esto destruirá su desempeño.
gberger
8
de pyspark.sql.functions importar from_unixtime, unix_timestamp
Quetzalcoatl
Tenga en cuenta que puede encontrar una referencia de formato de fecha de Java aquí: docs.oracle.com/javase/6/docs/api/java/text/…
RobinL
3
También tenga en cuenta que to_date()con el argumento de formato es Spark 2.2+. to_dateexistía antes de 2.2, pero la opción de formato no existía
RobinL
41
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()

Aquí está el resultado:

+----------+----------+----------+----------+
|     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)
Hugo Reyes
fuente
6
A udfno debería ser necesario en este caso, pero los muebles empotrados para el manejo de esto son atroz. Esto es lo que haría yo también por ahora.
Jeff
3
¿Por qué las fechas de la columna de prueba no coinciden con la primera columna? Sí, ahora es del tipo de fecha, pero los días y los meses no coinciden. ¿Hay una razón?
Jenks
1
La prueba da valores incorrectos para la fecha. Ésta no es la respuesta correcta.
Shehryar
1
Cualquier solución con UDF no es una respuesta, apenas una solución. No creo que haya muchos casos de uso que no se pueden hacer combinando PSF y .transform ().
sumon c
28

El enfoque strptime () no me funciona. Obtengo otra solución más limpia, 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 |
Franco
fuente
7
¡Gracias, este enfoque funcionó para mí! En caso de que alguien quiera convertir una cadena como 2008-08-01T14:45:37Zuna marca de tiempo en lugar de una fecha, df = df.withColumn("CreationDate",df['CreationDate'].cast(TimestampType()))funciona bien ... (Spark 2.2.0)
Gaurav
1
Probé esta opción entre muchas de AWS Glue pyspark, ¡funciona a la perfección!
Abhi
11

En la actualización de la respuesta aceptada, no ve el ejemplo de la to_datefunción, por lo que otra solución que la use sería:

from pyspark.sql import functions as F

df = df.withColumn(
            'new_date',
                F.to_date(
                    F.unix_timestamp('STRINGCOLUMN', 'MM-dd-yyyy').cast('timestamp')))
Manrique
fuente
1
hacer un simple to_date () no funciona, esta es la respuesta correcta
ski_squaw
6

posiblemente no tantas respuestas, así que estoy pensando en compartir mi código, lo que puede ayudar a alguien

from pyspark.sql import SparkSession
from pyspark.sql.functions import to_date

spark = SparkSession.builder.appName("Python Spark SQL basic example")\
    .config("spark.some.config.option", "some-value").getOrCreate()


df = spark.createDataFrame([('2019-06-22',)], ['t'])
df1 = df.select(to_date(df.t, 'yyyy-MM-dd').alias('dt'))
print df1
print df1.show()

salida

DataFrame[dt: date]
+----------+
|        dt|
+----------+
|2019-06-22|
+----------+

el código anterior para convertir a la fecha si desea convertir la fecha y hora, luego use to_timestamp. Hazme saber si tienes alguna duda.

Santosh kumar Manda
fuente
1

Prueba esto:

df = spark.createDataFrame([('2018-07-27 10:30:00',)], ['Date_col'])
df.select(from_unixtime(unix_timestamp(df.Date_col, 'yyyy-MM-dd HH:mm:ss')).alias('dt_col'))
df.show()
+-------------------+  
|           Date_col|  
+-------------------+  
|2018-07-27 10:30:00|  
+-------------------+  
Vishwajeet Pol
fuente
7
Puede considerar la posibilidad de explicar cómo su respuesta mejora lo que ya se ha proporcionado y aceptado.
chb