[PYTHON] Précautions lors du calcul avec une chaîne pour TmeStampType de PySpark

introduction

Il est dit qu'il existe un modèle qui se comporte involontairement si le type de chaîne de caractères du format de date est utilisé avec négligence lors du calcul de TimeStampType de PySpark.

Par conséquent, il est possible de calculer avec une chaîne pour TimeStampType, mais il est plus sûr d'utiliser datetime.

Exemple

Un exemple spécifique sera décrit.

L'exemple présenté ici provient de PySPark 2.4.4.

Données de vérification

Avec le code suivant, créez un Spark DataFrame avec des données de date du 1er janvier 2000 au 5 janvier 2000 et effectuez un traitement conditionnel sur ces données de date.

Données de vérification


import pandas as pd
from pyspark.sql import functions as F

pdf = pd.DataFrame(pd.date_range(start='1/1/2000', periods=5), columns=['date'])
sdf = spark.createDataFrame(pdf, ['timestamp'])

Calcul de TimeStampType et de datetime

L'opération utilisant datetime pour TimeStampType fonctionne normalement.

Calcul de TimeStampType et de datetime


target_datetime = datetime.strptime('2000-01-03', '%Y-%m-%d')

print('== datetime(2000-01-03)')
sdf.where(F.col('timestamp') == datetime.strptime('2000-01-03', '%Y-%m-%d')).show()
print('>  datetime(2000-01-03)')
sdf.where(F.col('timestamp') >  datetime.strptime('2000-01-03', '%Y-%m-%d')).show()
print('>= datetime(2000-01-03)')
sdf.where(F.col('timestamp') >= datetime.strptime('2000-01-03', '%Y-%m-%d')).show()
print('<  datetime(2000-01-03)')
sdf.where(F.col('timestamp') <  datetime.strptime('2000-01-03', '%Y-%m-%d')).show()
print('<= datetime(2000-01-03)')
sdf.where(F.col('timestamp') <= datetime.strptime('2000-01-03', '%Y-%m-%d')).show()
print('between datetime(2000-01-02) and datetime(2000-01-04)')
sdf.where(F.col('timestamp').between(datetime.strptime('2000-01-02', '%Y-%m-%d'), datetime.strptime('2000-01-04', '%Y-%m-%d'))).show()

Résultat de sortie


== datetime(2000-01-03)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-03 00:00:00|
+-------------------+

>  datetime(2000-01-03)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-04 00:00:00|
|2000-01-05 00:00:00|
+-------------------+

>= datetime(2000-01-03)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-03 00:00:00|
|2000-01-04 00:00:00|
|2000-01-05 00:00:00|
+-------------------+

<  datetime(2000-01-03)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-01 00:00:00|
|2000-01-02 00:00:00|
+-------------------+

<= datetime(2000-01-03)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-01 00:00:00|
|2000-01-02 00:00:00|
|2000-01-03 00:00:00|
+-------------------+

between datetime(2000-01-02) and datetime(2000-01-04)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-02 00:00:00|
|2000-01-03 00:00:00|
|2000-01-04 00:00:00|
+-------------------+

Calcul de TimeStampType et de la chaîne (format datetime)

Ensuite, le résultat lorsque la chaîne est donnée au format datetime (aaaa-mm-jj hh: mm: ss) est affiché. string semble être transtypé implicitement et les opérations peuvent être effectuées sans problème.

TimeStampType et chaîne(format datetime)Calcul


print('== string(2000-01-03 00:00:00)')
sdf.where(F.col('timestamp') == '2000-01-03 00:00:00').show()
print('>  string(2000-01-03 00:00:00)')
sdf.where(F.col('timestamp') >  '2000-01-03 00:00:00').show()
print('>= string(2000-01-03 00:00:00)')
sdf.where(F.col('timestamp') >= '2000-01-03 00:00:00').show()
print('<  string(2000-01-03 00:00:00)')
sdf.where(F.col('timestamp') <  '2000-01-03 00:00:00').show()
print('<= string(2000-01-03 00:00:00)')
sdf.where(F.col('timestamp') <= '2000-01-03 00:00:00').show()
print('between string(2000-01-02 00:00:00) and string(2000-01-04 00:00:00)')
sdf.where(F.col('timestamp').between('2000-01-02 00:00:00', '2000-01-04 00:00:00')).show()

Résultat de sortie


== string(2000-01-03 00:00:00)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-03 00:00:00|
+-------------------+

>  string(2000-01-03 00:00:00)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-04 00:00:00|
|2000-01-05 00:00:00|
+-------------------+

>= string(2000-01-03 00:00:00)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-03 00:00:00|
|2000-01-04 00:00:00|
|2000-01-05 00:00:00|
+-------------------+

<  string(2000-01-03 00:00:00)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-01 00:00:00|
|2000-01-02 00:00:00|
+-------------------+

<= string(2000-01-03 00:00:00)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-01 00:00:00|
|2000-01-02 00:00:00|
|2000-01-03 00:00:00|
+-------------------+

between string(2000-01-02 00:00:00) and string(2000-01-04 00:00:00)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-02 00:00:00|
|2000-01-03 00:00:00|
|2000-01-04 00:00:00|
+-------------------+

Calcul de TimeStampType et chaîne (format de date)

Enfin, le résultat lorsque la chaîne est donnée au format date (aaaa-mm-jj) est affiché. Dans ce cas, il existe un modèle qui entraîne un comportement qui n'est pas intuitivement prévu.

TimeStampType et chaîne(format de date)Calcul


print('== string(2000-01-03)')
sdf.where(F.col('timestamp') == '2000-01-03').show()
print('>  string(2000-01-03)')  #Motif involontaire
sdf.where(F.col('timestamp') >  '2000-01-03').show()
print('>= string(2000-01-03)')
sdf.where(F.col('timestamp') >= '2000-01-03').show()
print('<  string(2000-01-03)')
sdf.where(F.col('timestamp') <  '2000-01-03').show()
print('<= string(2000-01-03)')  #Motif involontaire
sdf.where(F.col('timestamp') <= '2000-01-03').show()
print('between string(2000-01-02) and string(2000-01-04)')  #Motif involontaire
sdf.where(F.col('timestamp').between('2000-01-02', '2000-01-04')).show()

Résultat de sortie


== string(2000-01-03)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-03 00:00:00|
+-------------------+

>  string(2000-01-03)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-03 00:00:00|
|2000-01-04 00:00:00|
|2000-01-05 00:00:00|
+-------------------+

>= string(2000-01-03)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-03 00:00:00|
|2000-01-04 00:00:00|
|2000-01-05 00:00:00|
+-------------------+

<  string(2000-01-03)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-01 00:00:00|
|2000-01-02 00:00:00|
+-------------------+

<= string(2000-01-03)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-01 00:00:00|
|2000-01-02 00:00:00|
+-------------------+

between string(2000-01-02) and string(2000-01-04)
+-------------------+
|          timestamp|
+-------------------+
|2000-01-02 00:00:00|
|2000-01-03 00:00:00|
+-------------------+

À propos du comportement

En raison de la conversion implicite de la chaîne en TimeStamp au moment de l'opération, «TimeStamp (2000-01-01 00:00:00)» et «TimeStamp (string (2000-01-01 00:00:00))» sont équivalents. Et le résultat est comme TimeStamp (2000-01-01 00:00:00) <TimeStamp (string (2000-01-01)).

À partir de là, on peut imaginer que les valeurs des heures («00: 00: 00» dans l'exemple ci-dessus) ne sont pas traitées correctement. (Pour des spécifications strictes, vous devez vérifier la source Scala pour les détails de l'opération)

(Édition supplémentaire) Transtyper du type de chaîne au type d'horodatage

À propos, lors de la conversion de StringType en TimeStampType, il semble que la conversion soit correcte. Un exemple n'est pas montré ici, mais comme avec le modèle ci-dessus, même si le traitement arithmétique avec TimeStampType est effectué, il fonctionne normalement (naturellement car il est entre les types TimeStampType).

Conversion de StringType en TimeStampType


df = spark.createDataFrame([('2000',), ('2000-01-01',), ('2000-01-01 00:00:00',) ], ['str'])
df = df.withColumn('timestamp', F.col('str').cast('timestamp'))
df.show()

Résultat de sortie


+-------------------+-------------------+
|                str|          timestamp|
+-------------------+-------------------+
|               2000|2000-01-01 00:00:00|
|         2000-01-01|2000-01-01 00:00:00|
|2000-01-01 00:00:00|2000-01-01 00:00:00|
+-------------------+-------------------+

Recommended Posts

Précautions lors du calcul avec une chaîne pour TmeStampType de PySpark
Récapitulatif des outils d'exploitation de l'interface graphique Windows avec Python
Précautions lors de l'installation de tensorflow avec anaconda
Faites attention à LANG pour UnicodeEncodeError lors de l'impression du japonais avec Python 3
À propos des transactions lors de l'utilisation de PostgreSQL avec Psycopg2
Mesurer la similitude du contenu avec Pyspark
4ème nuit de boucle avec pour
Précautions lors de l'utilisation de six avec Python 2.5
Points à noter lors de la résolution de problèmes DP avec Python
Précautions lors de l'utilisation de l'instruction for dans les pandas
Résumé de l'extrait de code lors du développement avec Go
La troisième nuit de la boucle avec pour
Mémorandum de migration avec GORM
La deuxième nuit de la boucle avec pour
Un mémorandum de méthode souvent utilisé lors de l'analyse de données avec des pandas (pour les débutants)
Précautions lors du traitement des structures de contrôle dans Python 2.6
Précautions lors de l'utilisation de tf.keras.layers.TimeDistributed pour la couche personnalisée tf.keras
Précautions lors de l'utilisation de la bibliothèque google-cloud avec GAE / py
[Développement Web avec Python] Précautions lors de l'enregistrement des cookies