Konwertuj ciąg pyspark na format daty

80

Mam ramkę danych pyspark daty z kolumną typu string w formacie MM-dd-yyyyi próbuję przekonwertować ją na kolumnę daty.

Próbowałem:

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

i otrzymuję ciąg wartości null. Czy ktoś może pomóc?

Jenks
źródło
O ile nie używasz jednego z dodatków TimeSeriesRDD (zobacz konferencję Spark 2016 w celu omówienia, są dwa, o których wiem, ale oba są nadal w fazie rozwoju), nie ma wielu świetnych narzędzi do szeregów czasowych. W związku z tym stwierdziłem, że rzadko istnieje powód, aby zawracać sobie głowę konwertowaniem ciągów znaków na obiekty typu data-godzina, jeśli Twoim celem są prawdziwe typy groupBylub operacje ponownego próbkowania. Po prostu wykonaj je na kolumnach strun.
Jeff
Analiza zostanie przeprowadzona przy użyciu niewielkich lub żadnych, groupByale raczej podłużnych badań dokumentacji medycznej. Dlatego ważna jest możliwość manipulowania datą
Jenks

Odpowiedzi:

114

Aktualizacja (10.01.2018):

W przypadku platformy Spark 2.2+ najlepszym sposobem na to jest prawdopodobnie użycie funkcji to_datelub to_timestamp, które obsługują formatargument. Z dokumentów:

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

Oryginalna odpowiedź (dla Spark <2.2)

Jest możliwe (preferowane?) Zrobienie tego bez 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
źródło
3
To jest poprawna odpowiedź. Użycie do tego celu udf zniszczy Twoją wydajność.
gberger
8
from pyspark.sql.functions import from_unixtime, unix_timestamp
Quetzalcoatl
Zauważ, że możesz znaleźć odniesienie do formatu daty w Javie tutaj: docs.oracle.com/javase/6/docs/api/java/text/…
RobinL
3
Zauważ również, że to_date()argumentem format jest spark 2.2+. to_dateistniał przed 2.2, ale opcja formatu nie istniał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()

Oto wynik:

+----------+----------+----------+----------+
|     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
źródło
6
A udfnie powinno być tutaj konieczne, ale wbudowane funkcje do obsługi tego są okropne. Na razie to też bym zrobił.
Jeff
3
Dlaczego daty w kolumnie testowej nie zgadzają się z pierwszą kolumną? Tak, teraz jest to typ daty, ale dni i miesiące nie są zgodne. Czy jest powód?
Jenks
1
test podaje nieprawidłowe wartości daty. To nie jest dobra odpowiedź.
Shehryar
1
Każde rozwiązanie z UDF nie jest odpowiedzią, ledwie obejściem. Nie sądzę, jest wiele przypadków użycia, których nie można zrobić, łącząc sam PSF i .transform ().
sumon c
28

Podejście strptime () nie działa dla mnie. Otrzymuję inne czystsze rozwiązanie, używając odlewu:

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 |
Szczery
źródło
7
Dzięki, to podejście zadziałało dla mnie! Na wypadek, gdyby ktoś chciał przekonwertować ciąg, taki jak 2008-08-01T14:45:37Zznacznik czasu zamiast daty, df = df.withColumn("CreationDate",df['CreationDate'].cast(TimestampType()))działa dobrze ... (Spark 2.2.0)
Gaurav
1
Wypróbowałem tę opcję spośród wielu z AWS Glue pyspark, działa jak urok!
Abhi
11

W aktualizacji zaakceptowanej odpowiedzi nie widzisz przykładu dla to_datefunkcji, więc innym rozwiązaniem wykorzystującym ją byłoby:

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
źródło
1
wykonanie prostej metody to_date () nie działa, to jest poprawna odpowiedź
ski_squaw
6

prawdopodobnie nie tak wiele odpowiedzi, więc myślę o udostępnieniu mojego kodu, który może komuś pomóc

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

wynik

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

powyższy kod, aby przekonwertować na datę, jeśli chcesz przekonwertować datę i godzinę, a następnie użyj to_timestamp. daj mi znać, jeśli masz jakiekolwiek wątpliwości.

Santosh kumar Manda
źródło
1

Spróbuj tego:

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
źródło
7
Możesz rozważyć wyjaśnienie, w jaki sposób Twoja odpowiedź poprawia to, co zostało już przekazane i zaakceptowane.
chb