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.
Ê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()
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"))
_
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)
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())
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é.
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)
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.
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)
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()
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
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)