web-dev-qa-db-fra.com

Charger le fichier CSV avec Spark

Je suis nouveau sur Spark et j'essaie de lire des données CSV à partir d'un fichier avec Spark. Voici ce que je fais:

sc.textFile('file.csv')
    .map(lambda line: (line.split(',')[0], line.split(',')[1]))
    .collect()

Je m'attendrais à ce que cet appel me donne une liste des deux premières colonnes de mon fichier, mais j'obtiens cette erreur:

File "<ipython-input-60-73ea98550983>", line 1, in <lambda>
IndexError: list index out of range

bien que mon fichier CSV ait plus d’une colonne.

90
Kernael

Êtes-vous sûr que toutes les lignes ont au moins 2 colonnes? Pouvez-vous essayer quelque chose du genre, juste pour vérifier ?:

sc.textFile("file.csv") \
    .map(lambda line: line.split(",")) \
    .filter(lambda line: len(line)>1) \
    .map(lambda line: (line[0],line[1])) \
    .collect()

Alternativement, vous pouvez imprimer le coupable (le cas échéant):

sc.textFile("file.csv") \
    .map(lambda line: line.split(",")) \
    .filter(lambda line: len(line)<=1) \
    .collect()
58
G Quintana

Spark 2.0.0 +

Vous pouvez utiliser directement la source de données csv intégrée:

_spark.read.csv(
    "some_input_file.csv", header=True, mode="DROPMALFORMED", schema=schema
)
_

ou

_(spark.read
    .schema(schema)
    .option("header", "true")
    .option("mode", "DROPMALFORMED")
    .csv("some_input_file.csv"))
_

sans inclure aucune dépendance externe.

Spark <2.0.0 :

Au lieu d'analyser manuellement, ce qui est loin d'être trivial dans un cas général, je recommanderais spark-csv :

Assurez-vous que Spark CSV est inclus dans le chemin (_--packages_, _--jars_, _--driver-class-path_)

Et chargez vos données comme suit:

_(df = sqlContext
    .read.format("com.databricks.spark.csv")
    .option("header", "true")
    .option("inferschema", "true")
    .option("mode", "DROPMALFORMED")
    .load("some_input_file.csv"))
_

Il peut gérer le chargement, l'inférence de schéma, la suppression de lignes mal formées et ne nécessite pas le transfert de données de Python à la machine virtuelle Java.

Remarque :

Si vous connaissez le schéma, il est préférable d'éviter l'inférence de schéma et de le transmettre à DataFrameReader. En supposant que vous ayez trois colonnes - entier, double et chaîne:

_from pyspark.sql.types import StructType, StructField
from pyspark.sql.types import DoubleType, IntegerType, StringType

schema = StructType([
    StructField("A", IntegerType()),
    StructField("B", DoubleType()),
    StructField("C", StringType())
])

(sqlContext
    .read
    .format("com.databricks.spark.csv")
    .schema(schema)
    .option("header", "true")
    .option("mode", "DROPMALFORMED")
    .load("some_input_file.csv"))
_
157
zero323

Et encore une autre option qui consiste à lire le fichier CSV en utilisant Pandas puis à importer le Pandas DataFrame dans Spark.

Par exemple:

from pyspark import SparkContext
from pyspark.sql import SQLContext
import pandas as pd

sc = SparkContext('local','example')  # if using locally
sql_sc = SQLContext(sc)

pandas_df = pd.read_csv('file.csv')  # assuming the file contains a header
# pandas_df = pd.read_csv('file.csv', names = ['column 1','column 2']) # if no header
s_df = sql_sc.createDataFrame(pandas_df)
16
JP Mercier
from pyspark.sql import SparkSession

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

df = spark.read.csv("/home/stp/test1.csv",header=True,sep="|");

print(df.collect())
15
y durga prasad

Le simple fait de scinder par virgule divise également les virgules situées dans les champs (par exemple, a,b,"1,2,3",c), ce qui n’est donc pas recommandé. La réponse de zero32 C'est bien si vous voulez utiliser l'API DataFrames, mais si vous voulez vous en tenir à la base Spark, vous pouvez analyser les fichiers CSV dans la base Python avec le csv module:

# works for both python 2 and 3
import csv
rdd = sc.textFile("file.csv")
rdd = rdd.mapPartitions(lambda x: csv.reader(x))

EDIT: Comme @muon l'a mentionné dans les commentaires, l'en-tête sera traité comme n'importe quelle autre ligne. Vous devrez donc l'extraire manuellement. Par exemple, header = rdd.first(); rdd = rdd.filter(lambda x: x != header) (veillez à ne pas modifier header avant l'évaluation du filtre). Mais à ce stade, il vaut probablement mieux utiliser un analyseur syntaxique CSV intégré.

15
Galen Long

Maintenant, il y a aussi une autre option pour tout fichier csv général: https://github.com/seahboonsiew/pyspark-csv comme suit:

Supposons que nous avons le contexte suivant

sc = SparkContext
sqlCtx = SQLContext or HiveContext

Tout d'abord, distribuez pyspark-csv.py aux exécuteurs à l'aide de SparkContext

import pyspark_csv as pycsv
sc.addPyFile('pyspark_csv.py')

Lisez les données csv via SparkContext et convertissez-les en DataFrame

plaintext_rdd = sc.textFile('hdfs://x.x.x.x/blah.csv')
dataframe = pycsv.csvToDataFrame(sqlCtx, plaintext_rdd)
5
optimist

Si vous voulez charger csv en tant que structure de données, vous pouvez procéder comme suit:

from pyspark.sql import SQLContext
sqlContext = SQLContext(sc)

df = sqlContext.read.format('com.databricks.spark.csv') \
    .options(header='true', inferschema='true') \
    .load('sampleFile.csv') # this is your csv file

Cela a bien fonctionné pour moi.

4
Jeril

Si vos données csv ne contiennent aucune nouvelle ligne dans aucun des champs, vous pouvez charger vos données avec textFile() et les analyser.

import csv
import StringIO

def loadRecord(line):
    input = StringIO.StringIO(line)
    reader = csv.DictReader(input, fieldnames=["name1", "name2"])
    return reader.next()

input = sc.textFile(inputFile).map(loadRecord)
3
iec2011007

Ceci est conforme à ce que JP Mercier avait initialement suggéré sur l’utilisation des Pandas, mais avec une modification majeure: si vous lisez des données dans Pandas en morceaux, il devrait être plus malléable. Cela signifie que vous pouvez analyser un fichier beaucoup plus volumineux que Pandas ne peut en réalité gérer qu'un seul fichier et le transmettre à Spark dans des tailles plus petites. (Ceci répond également au commentaire sur pourquoi on voudrait utiliser Spark s’ils peuvent tout charger dans Pandas de toute façon.)

from pyspark import SparkContext
from pyspark.sql import SQLContext
import pandas as pd

sc = SparkContext('local','example')  # if using locally
sql_sc = SQLContext(sc)

Spark_Full = sc.emptyRDD()
chunk_100k = pd.read_csv("Your_Data_File.csv", chunksize=100000)
# if you have headers in your csv file:
headers = list(pd.read_csv("Your_Data_File.csv", nrows=0).columns)

for chunky in chunk_100k:
    Spark_Full +=  sc.parallelize(chunky.values.tolist())

YourSparkDataFrame = Spark_Full.toDF(headers)
# if you do not have headers, leave empty instead:
# YourSparkDataFrame = Spark_Full.toDF()
YourSparkDataFrame.show()
3
abby sobh

Si vous avez une ou plusieurs lignes avec moins ou plus de colonnes que 2 dans le jeu de données, cette erreur peut survenir.

Je suis également nouveau sur Pyspark et essaie de lire le fichier CSV. Le code suivant a fonctionné pour moi:

Dans ce code, j'utilise le jeu de données de kaggle, le lien est le suivant: https://www.kaggle.com/carrie1/ecommerce-data

1. Sans mentionner le schéma:

from pyspark.sql import SparkSession  
scSpark = SparkSession \
    .builder \
    .appName("Python Spark SQL basic example: Reading CSV file without mentioning schema") \
    .config("spark.some.config.option", "some-value") \
    .getOrCreate()

sdfData = scSpark.read.csv("data.csv", header=True, sep=",")
sdfData.show()

Maintenant, vérifiez les colonnes: sdfData.columns

La sortie sera:

['InvoiceNo', 'StockCode','Description','Quantity', 'InvoiceDate', 'CustomerID', 'Country']

Vérifiez le type de données pour chaque colonne:

sdfData.schema
StructType(List(StructField(InvoiceNo,StringType,true),StructField(StockCode,StringType,true),StructField(Description,StringType,true),StructField(Quantity,StringType,true),StructField(InvoiceDate,StringType,true),StructField(UnitPrice,StringType,true),StructField(CustomerID,StringType,true),StructField(Country,StringType,true)))

Cela donnera le cadre de données avec toutes les colonnes avec le type de données comme StringType

2. Avec schéma: Si vous connaissez le schéma ou voulez changer le type de données d’une colonne du tableau ci-dessus, utilisez ceci (supposons que j’ai des colonnes suivantes et que je les veux dans un type de données particulier pour chacune d'entre elles)

from pyspark.sql import SparkSession  
from pyspark.sql.types import StructType, StructField
from pyspark.sql.types import DoubleType, IntegerType, StringType
    schema = StructType([\
        StructField("InvoiceNo", IntegerType()),\
        StructField("StockCode", StringType()), \
        StructField("Description", StringType()),\
        StructField("Quantity", IntegerType()),\
        StructField("InvoiceDate", StringType()),\
        StructField("CustomerID", DoubleType()),\
        StructField("Country", StringType())\
    ])

scSpark = SparkSession \
    .builder \
    .appName("Python Spark SQL example: Reading CSV file with schema") \
    .config("spark.some.config.option", "some-value") \
    .getOrCreate()

sdfData = scSpark.read.csv("data.csv", header=True, sep=",", schema=schema)

Maintenant, vérifiez le schéma pour le type de données de chaque colonne:

sdfData.schema

StructType(List(StructField(InvoiceNo,IntegerType,true),StructField(StockCode,StringType,true),StructField(Description,StringType,true),StructField(Quantity,IntegerType,true),StructField(InvoiceDate,StringType,true),StructField(CustomerID,DoubleType,true),StructField(Country,StringType,true)))

Modifié: Nous pouvons également utiliser la ligne de code suivante sans mentionner explicitement le schéma:

sdfData = scSpark.read.csv("data.csv", header=True, inferSchema = True)
sdfData.schema

La sortie est:

StructType(List(StructField(InvoiceNo,StringType,true),StructField(StockCode,StringType,true),StructField(Description,StringType,true),StructField(Quantity,IntegerType,true),StructField(InvoiceDate,StringType,true),StructField(UnitPrice,DoubleType,true),StructField(CustomerID,IntegerType,true),StructField(Country,StringType,true)))

La sortie ressemblera à ceci:

sdfData.show()

+---------+---------+--------------------+--------+--------------+----------+-------+
|InvoiceNo|StockCode|         Description|Quantity|   InvoiceDate|CustomerID|Country|
+---------+---------+--------------------+--------+--------------+----------+-------+
|   536365|   85123A|WHITE HANGING HEA...|       6|12/1/2010 8:26|      2.55|  17850|
|   536365|    71053| WHITE METAL LANTERN|       6|12/1/2010 8:26|      3.39|  17850|
|   536365|   84406B|CREAM CUPID HEART...|       8|12/1/2010 8:26|      2.75|  17850|
|   536365|   84029G|KNITTED UNION FLA...|       6|12/1/2010 8:26|      3.39|  17850|
|   536365|   84029E|RED WOOLLY HOTTIE...|       6|12/1/2010 8:26|      3.39|  17850|
|   536365|    22752|SET 7 BABUSHKA NE...|       2|12/1/2010 8:26|      7.65|  17850|
|   536365|    21730|GLASS STAR FROSTE...|       6|12/1/2010 8:26|      4.25|  17850|
|   536366|    22633|HAND WARMER UNION...|       6|12/1/2010 8:28|      1.85|  17850|
|   536366|    22632|HAND WARMER RED P...|       6|12/1/2010 8:28|      1.85|  17850|
|   536367|    84879|ASSORTED COLOUR B...|      32|12/1/2010 8:34|      1.69|  13047|
|   536367|    22745|POPPY'S PLAYHOUSE...|       6|12/1/2010 8:34|       2.1|  13047|
|   536367|    22748|POPPY'S PLAYHOUSE...|       6|12/1/2010 8:34|       2.1|  13047|
|   536367|    22749|FELTCRAFT PRINCES...|       8|12/1/2010 8:34|      3.75|  13047|
|   536367|    22310|IVORY KNITTED MUG...|       6|12/1/2010 8:34|      1.65|  13047|
|   536367|    84969|BOX OF 6 ASSORTED...|       6|12/1/2010 8:34|      4.25|  13047|
|   536367|    22623|BOX OF VINTAGE JI...|       3|12/1/2010 8:34|      4.95|  13047|
|   536367|    22622|BOX OF VINTAGE AL...|       2|12/1/2010 8:34|      9.95|  13047|
|   536367|    21754|HOME BUILDING BLO...|       3|12/1/2010 8:34|      5.95|  13047|
|   536367|    21755|LOVE BUILDING BLO...|       3|12/1/2010 8:34|      5.95|  13047|
|   536367|    21777|RECIPE BOX WITH M...|       4|12/1/2010 8:34|      7.95|  13047|
+---------+---------+--------------------+--------+--------------+----------+-------+
only showing top 20 rows
1
Yogesh

Lors de l'utilisation de spark.read.csv, l'utilisation des options escape='"' et multiLine=True constitue la solution la plus cohérente à norme CSV , et mon expérience donne les meilleurs résultats avec Fichiers CSV exportés à partir de Google Sheets.

C'est,

#set inferSchema=False to read everything as string
df = spark.read.csv("myData.csv", escape='"', multiLine=True,
     inferSchema=False, header=True)
1
flow2k