CSV dosyasını Spark ile yükle


110

Spark'ta yeniyim ve Spark ile bir dosyadan CSV verilerini okumaya çalışıyorum. İşte yaptığım şey:

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

Bu çağrının bana dosyamın ilk iki sütununun bir listesini vermesini beklerdim ama şu hatayı alıyorum:

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

CSV dosyam birden fazla sütun olmasına rağmen.

Yanıtlar:


63

Tüm satırların en az 2 sütun içerdiğinden emin misiniz ? Şöyle bir şey deneyebilir misin, sadece kontrol etmek için ?:

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

Alternatif olarak, suçluyu (varsa) yazdırabilirsiniz:

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

Hepsi buydu, tek sütunlu tek satır, teşekkürler.
Kernael

2
csvTüm kaçışları işlemek için yerleşik kitaplığı kullanarak ayrıştırmak daha iyidir çünkü, örneğin değerlerde virgül varsa, virgülle ayırmak işe yaramaz.
sudo

4
Csv'yi ayrıştırmak için pek çok araç var, tekerleği yeniden keşfetmeyin
Stephen

2
Tırnak içinde virgül varsa bu kod kırılacaktır. Csv'yi ayrıştırmak, yalnızca bölmek yerine daha karmaşıktır ",".
Alceu Costa

Bu, virgül için kırılır. Bu çok kötü.
rjurney

184

Spark 2.0.0+

Yerleşik csv veri kaynağını doğrudan kullanabilirsiniz:

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

veya

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

herhangi bir dış bağımlılık dahil etmeden.

Kıvılcım <2.0.0 :

Genel bir durumda önemsiz olmaktan çok uzak olan manuel ayrıştırma yerine spark-csvşunları tavsiye ederim :

Emin Spark CSV yolu dahil olduğundan emin olun ( --packages, --jars, --driver-class-path)

Verilerinizi aşağıdaki gibi yükleyin:

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

Yüklemeyi, şema çıkarımını işleyebilir, hatalı biçimlendirilmiş satırları kaldırabilir ve Python'dan JVM'ye veri aktarımı gerektirmez.

Not :

Şemayı biliyorsanız, şema çıkarımından kaçınmak ve onu iletmek daha iyidir DataFrameReader. Üç sütununuz olduğunu varsayarsak - tamsayı, çift ve dize:

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

6
Bunu yaparsanız, pyspark kabuğunu açtığınızda veya spark-submit kullandığınızda databricks csv paketini dahil etmeyi unutmayın. Örneğin, pyspark --packages com.databricks:spark-csv_2.11:1.4.0(databricks / spark sürümlerini yüklediğiniz sürümlerle değiştirdiğinizden emin olun).
Galen Long

Pyspark'ta csvContext veya sqlContext mi? Çünkü ölçek olarak csvContext'e ihtiyacınız var
Geoffrey Anderson

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

aşağıdaki gibi 'sep not' ayırıcı 'kullanın: df = spark.read.csv ("/ home / stp / test1.csv", header = True, sep = "|")
Shannon'a

18

Ve yine Pandas kullanarak CSV dosyasını okumak ve ardından Pandas DataFrame'i Spark'a aktarmaktan oluşan başka bir seçenek.

Örneğin:

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)

7
OP pandalara veri yükleyebiliyorsa neden kıvılcım
atmak ister?

Her kıvılcım kümesine bağımlılık yüklemek veya belirtmek istemiyorum ....
SummerEla

Panda, okurken dosya yığınlamaya izin verir, bu nedenle burada Pandaların ilk dosya ayrıştırmasını gerçekleştirmesi için hala bir kullanım durumu vardır. Kod için aşağıdaki cevabıma bakın.
abby sobh

Dikkat: Pandalar ayrıca sütun şemasını kıvılcımdan farklı bir şekilde ele alır, özellikle de boşluklar olduğunda. Csv'yi her sütun için dizeler olarak yüklemek daha güvenlidir.
AntiPawn79

@WoodChopper Pandaları Spark'ta UDF olarak kullanabilirsiniz, değil mi?
flow2k

16

Basitçe virgülle ayırmak, alanların içindeki virgülleri de böler (örn. a,b,"1,2,3",c), Bu nedenle önerilmez. Zero323'ün cevabı , DataFrames API'sini kullanmak istiyorsanız iyidir, ancak temel Spark'a bağlı kalmak istiyorsanız, csv'leri csv modülüyle temel Python'da ayrıştırabilirsiniz :

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

DÜZENLEME: @muon yorumlarda belirtildiği gibi, bu, başlığı başka herhangi bir satır gibi ele alacak, bu yüzden manuel olarak çıkarmanız gerekecek. Örneğin, header = rdd.first(); rdd = rdd.filter(lambda x: x != header)( headerfiltre değerlendirilmeden önce değişiklik yapmadığınızdan emin olun ). Ancak bu noktada, yerleşik bir csv ayrıştırıcısı kullanmanız muhtemelen daha iyidir.


1
DataFrame'leri kullanmak için Hive'a ihtiyacınız yok. Çözümünüzle ilgili olarak: a) Gerek yok StringIO. csvherhangi bir yinelenebilir kullanabilir b) __next__doğrudan kullanılmamalıdır ve boş satırda başarısız olur. FlatMap'e bir göz atın c) mapPartitionsOkuyucuyu her satırda başlatmak yerine kullanmak çok daha verimli olacaktır :)
zero323

Düzeltmeler için çok teşekkürler! Cevabımı düzenlemeden önce, tam olarak anladığımdan emin olmak istiyorum. 1) Bir hata rdd.mapPartitions(lambda x: csv.reader(x))atarken neden çalışıyor rdd.map(lambda x: csv.reader(x))? İkisinin de aynı şeyi atmasını bekliyordum TypeError: can't pickle _csv.reader objects. Gibi O da görünüyor mapPartitionsotomatik olarak "readlines" bazı eşdeğer çağırır csv.readerile nesne, mapben aramak gerektiğinde, __next__dışına listelerini almak için açıkça csv.reader. 2) Nereye giriyor flatMap? Sadece aramak mapPartitionsbenim için çalıştı.
Galen Long

1
rdd.mapPartitions(lambda x: csv.reader(x))çalışır çünkü mapPartitionsbir Iterablenesne beklemektedir . Açık olmak istiyorsanız, anlayabilirsiniz ya da ifade üretebilirsiniz. maptek başına çalışmaz çünkü nesne üzerinde yineleme yapmaz. Bu nedenle flatMap(lambda x: csv.reader([x])), okuyucu üzerinde yinelenecek olan kullanma önerim . Ama mapPartitionsburada çok daha iyi.
zero323

1
bunun üstbilgiyi başlık olarak değil, bir veri satırı olarak okuyacağını unutmayın
muon

7

Bu PYSPARK'ta

path="Your file path with file name"

df=spark.read.format("csv").option("header","true").option("inferSchema","true").load(path)

O zaman kontrol edebilirsin

df.show(5)
df.count()

6

Csv'yi bir veri çerçevesi olarak yüklemek istiyorsanız, aşağıdakileri yapabilirsiniz:

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

Benim için iyi çalıştı.


@GalenLong eğer sakıncası yoksa, zaten var olan cevabı paylaşır
mısın

Garip, yemin ederim bu çözümün başka bir cevabı vardı. Belki bunu başka bir soruyla karıştırdım. Benim hatam.
Galen Long

5

Bu, JP Mercier'ın Pandaları kullanma konusunda başlangıçta önerdiği şeyle uyumludur , ancak büyük bir değişiklikle: Verileri Pandalar halinde parçalar halinde okursanız, daha kolay şekillendirilebilir olmalıdır. Yani, Pandaların aslında tek bir parça olarak işleyebileceğinden çok daha büyük bir dosyayı ayrıştırabilir ve daha küçük boyutlarda Spark'a aktarabilirsiniz. (Bu aynı zamanda, her şeyi Pandalar'a yükleyebiliyorlarsa, neden Spark'ı kullanmak isteyecekleri hakkındaki yorumu da yanıtlıyor.)

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

5

Şimdi, herhangi bir genel csv dosyası için başka bir seçenek daha var: https://github.com/seahboonsiew/pyspark-csv aşağıdaki gibi:

Aşağıdaki içeriğe sahip olduğumuzu varsayalım

sc = SparkContext
sqlCtx = SQLContext or HiveContext

İlk olarak, SparkContext kullanarak pyspark-csv.py'yi uygulayıcılara dağıtın

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

SparkContext aracılığıyla csv verilerini okuyun ve DataFrame'e dönüştürün

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

3

Csv verileriniz alanların hiçbirinde yeni satır içermiyorsa, verilerinizi yükleyip textFile()ayrıştırabilirsiniz.

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)

2

Veri kümesinde 2'den daha az veya daha fazla sayıda sütun içeren bir veya daha fazla satırınız varsa, bu hata ortaya çıkabilir.

Ayrıca Pyspark'ta yeniyim ve CSV dosyasını okumaya çalışıyorum. Aşağıdaki kod benim için çalıştı:

Bu kodda kaggle'dan veri setini kullanıyorum bağlantı: https://www.kaggle.com/carrie1/ecommerce-data

1. Şemadan bahsetmeden:

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

Şimdi sütunları kontrol edin: sdfData.columns

Çıktı şu şekilde olacaktır:

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

Her sütun için veri türünü kontrol edin:

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

Bu, veri çerçevesine StringType olarak veri türüne sahip tüm sütunları verecektir.

2. Şema ile: Şemayı biliyorsanız veya yukarıdaki tablodaki herhangi bir sütunun veri türünü değiştirmek istiyorsanız, bunu kullanın (diyelim ki aşağıdaki sütunlara sahibim ve her biri için belirli bir veri türünde olmasını istiyorum)

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)

Şimdi her bir sütunun veri türü için şemayı kontrol edin:

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

Düzenlendi: Şemadan açıkça bahsetmeden aşağıdaki kod satırını da kullanabiliriz:

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

Çıktı:

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

Çıktı şöyle görünecek:

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

Kullanırken spark.read.csv, ben seçeneklerini kullanarak bulmak escape='"'ve multiLine=Trueen tutarlı çözüm sağlamak CSV standart ve benim durumumda Google E ihraç dosyaları CSV ile iyi çalışır.

Yani,

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

kıvılcım nereden geliyor? öyle import pyspark as sparkmi
Luk Aron

@LukAron Bir pyspark kabuğunda, sparkzaten başlatıldı. Tarafından gönderilen bir komut dosyasında spark-submit, bunun örneğini oluşturabilirsiniz from pyspark.sql import SparkSession; spark = SparkSession.builder.getOrCreate().
flow2k
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.