web-dev-qa-db-fra.com

Lecture de fichiers csv avec des champs entre guillemets contenant des virgules incorporées

Je lis un fichier csv dans Pyspark comme suit:

df_raw=spark.read.option("header","true").csv(csv_path)

Cependant, le fichier de données contient des champs avec des virgules incorporées qui ne doivent pas être traités comme des virgules. Comment puis-je gérer cela dans Pyspark? Je sais pandas peut gérer cela, mais peut Spark? La version que j'utilise est Spark 2.0.0.

Voici un exemple qui fonctionne en Pandas mais échoue en utilisant Spark:

In [1]: import pandas as pd

In [2]: pdf = pd.read_csv('malformed_data.csv')

In [3]: sdf=spark.read.format("org.Apache.spark.csv").csv('malformed_data.csv',header=True)

In [4]: pdf[['col12','col13','col14']]
Out[4]:
                    col12                                             col13  \
0  32 XIY "W"   JK, RE LK  SOMETHINGLIKEAPHENOMENON#YOUGOTSOUL~BRINGDANOISE
1                     NaN                     OUTKAST#THROOTS~WUTANG#RUNDMC

   col14
0   23.0
1    0.0

In [5]: sdf.select("col12","col13",'col14').show()
+------------------+--------------------+--------------------+
|             col12|               col13|               col14|
+------------------+--------------------+--------------------+
|"32 XIY ""W""   JK|              RE LK"|SOMETHINGLIKEAPHE...|
|              null|OUTKAST#THROOTS~W...|                 0.0|
+------------------+--------------------+--------------------+

Le contenu du fichier:

    col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12,col13,col14,col15,col16,col17,col18,col19
80015360210876000,11.22,X,4076710258,,,sxsw,,"32 YIU ""A""",S5,,"32 XIY ""W""   JK, RE LK",SOMETHINGLIKEAPHENOMENON#YOUGOTSOUL~BRINGDANOISE,23.0,cyclingstats,2012-25-19,432,2023-05-17,CODERED
61670000229561918,137.12,U,8234971771,,,woodstock,,,T4,,,OUTKAST#THROOTS~WUTANG#RUNDMC,0.0,runstats,2013-21-22,1333,2019-11-23,CODEBLUE
19
femibyte

J'ai remarqué que votre ligne problématique s'est échappée et utilise des guillemets:

"32 XIY" "W" "JK, RE LK"

qui devrait être interprète tout comme

32 XIY "W" JK, RE LK

Comme décrit dans RFC-418 , page 2 -

  1. Si des guillemets doubles sont utilisés pour entourer des champs, un guillemet double apparaissant à l'intérieur d'un champ doit être échappé en le précédant d'un autre guillemet double

C'est ce que fait Excel, par exemple, par défaut.

Bien que dans Spark (à partir de Spark 2.1), l'échappement est effectué par défaut de manière non RFC, en utilisant backslah (\). Pour résoudre ce problème, vous devez pour dire explicitement Spark pour utiliser la double guillemet à utiliser comme caractère d'échappement:

.option('quote', '"')
.option('escape', '"')

Cela peut expliquer qu'un caractère virgule n'a pas été interprété comme il était à l'intérieur d'une colonne entre guillemets.

Les options pour le format Spark csv ne sont pas bien documentées sur le site Apache Spark, mais voici une documentation un peu plus ancienne que je trouve toujours utile assez souvent:

https://github.com/databricks/spark-csv

Mise à jour d'août 2018 : Spark 3.0 peut changer ce comportement pour être conforme aux RFC. Voir SPARK- 22236 pour plus de détails.

28
Tagar

Pour tous ceux qui font cela dans Scala: la réponse de Tagar a presque fonctionné pour moi (merci!); tout ce que j'avais à faire était d'échapper à la double citation lors du paramétrage de mon option:

.option("quote", "\"")
.option("escape", "\"")

J'utilise Spark 2.3, donc je peux confirmer que la solution de Tagar semble toujours fonctionner de la même manière dans la nouvelle version.

20
Allie Rogers

Le délimiteur (comma) spécifié dans quotes sera ignoré par défaut. Spark SQL a un lecteur CSV intégré dans Spark 2.0.

df = session.read
  .option("header", "true")
  .csv("csv/file/path")

plus d'informations sur le lecteur CSV ici - .

3
mrsrinivas