Завантажте файл CSV за допомогою іскри


110

Я новачок у Spark, і я намагаюся прочитати дані CSV з файлу із Spark. Ось що я роблю:

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

Я очікую, що цей дзвінок дасть мені список двох перших стовпців мого файлу, але я отримую цю помилку:

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

хоча мій файл CSV як більше одного стовпця.

Відповіді:


63

Ви впевнені, що всі рядки мають принаймні 2 стовпчики? Чи можете ви спробувати щось на кшталт, просто перевірити?

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

Ви також можете надрукувати винуватця (якщо такий є):

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

Це було все, один рядок із лише одним стовпчиком, дякую.
Кернаїл

2
Краще розібратися за допомогою вбудованої csvбібліотеки, щоб обробити всі протікають, оскільки просто розщеплення комою не буде працювати, якщо, скажімо, у значеннях є коми.
судо

4
Є багато інструментів для розбору csv, не винаходити колесо
Стівен

2
Цей код порушиться, якщо всередині лапок є кома. Розбір csv складніше, ніж просто розщеплення на ",".
Alceu Costa

Це розривається на коми. Це дуже погано.
rjurney

184

Іскра 2.0.0+

Ви можете використовувати вбудоване джерело даних csv безпосередньо:

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

або

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

без включення зовнішніх залежностей.

Іскра <2.0.0 :

Замість ручного розбору, який у загальному випадку далеко не банальний, я рекомендую spark-csv:

Переконайтеся в тому , що Спарк CSV включений в дорозі ( --packages, --jars, --driver-class-path)

І завантажте свої дані наступним чином:

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

Він може обробляти завантаження, висновок схеми, скидання неправильно сформованих ліній і не вимагає передачі даних з Python в JVM.

Примітка :

Якщо ви знаєте схему, краще уникати висновку схеми і передавати її DataFrameReader. Припустимо, що у вас є три стовпці - ціле, подвійне і рядкове:

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
Якщо ви це зробите, не забудьте включити пакет даних csv databricks, коли ви відкриєте оболонку pyspark або використовуєте іскрову подачу. Наприклад, pyspark --packages com.databricks:spark-csv_2.11:1.4.0(переконайтеся, що змінили версії даних / іскри на версії, які ви встановили).
Гален Лонг

Це csvContext або sqlContext в pyspark? Тому що в масштабі вам потрібен csvContext
Джеффрі Андерсон

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

використовувати 'sep not' separator 'так: df = spark.read.csv ("/ home / stp / test1.csv", header = True, sep = "|")
Грант Шеннон

18

І ще один варіант, який полягає в тому, щоб прочитати файл CSV за допомогою Pandas, а потім імпортувати DataFrame Pandas в Spark.

Наприклад:

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
Чому ОП хотів би зробити іскру, якщо він зможе завантажувати дані в
пандах

Не бажаючи встановлювати або вказувати залежності від кожного іскрового кластера ....
SummerEla

Panda дозволяє збирати файли під час читання, тому тут все ще є приклад використання для того, щоб Pandas обробляв початковий аналіз файлів. Дивіться мою відповідь нижче щодо коду.
abby sobh

Застереження: Pandas також обробляє схему стовпців способом інакше, ніж іскру, особливо коли є заготовки. Безпечніше просто завантажити csv у вигляді рядків для кожного стовпця.
AntiPawn79

@WoodChopper Ви можете використовувати Pandas як АДС в Spark, ні?
flow2k

16

Просто розщеплення комою також розділить коми, що знаходяться в полях (наприклад a,b,"1,2,3",c), тому це не рекомендується. Відповідь zero323 хороша, якщо ви хочете використовувати API DataFrames, але якщо ви хочете дотримуватися бази Spark, ви можете проаналізувати csvs в базовому Python за допомогою модуля csv :

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

EDIT: Як @muon згадується в коментарях, це стосуватиметься заголовка, як і будь-який інший рядок, тому вам потрібно буде витягнути його вручну. Наприклад, header = rdd.first(); rdd = rdd.filter(lambda x: x != header)(переконайтеся, що не змінювати, headerперш ніж фільтр оцінить). Але на даний момент вам, мабуть, краще використовувати вбудований аналізатор csv.


1
Вам не потрібен вулик для використання DataFrames. Щодо вашого рішення: а) Не потрібно StringIO. csvможе використовувати будь-який ітерабельний b) __next__не повинен використовуватися безпосередньо і вийде з ладу в порожньому рядку. Погляньте на flatMap c) Було б набагато ефективніше використовувати mapPartitionsзамість ініціалізації читача в кожному рядку :)
zero323

Дякую за виправлення! Перш ніж редагувати свою відповідь, я хочу переконатися, що я все розумію. 1) Чому rdd.mapPartitions(lambda x: csv.reader(x))працює, коли rdd.map(lambda x: csv.reader(x))видає помилку? Я очікував, що обидва кинуть те саме TypeError: can't pickle _csv.reader objects. Також здається, що mapPartitionsавтоматично викликає якийсь еквівалент "readlines" на csv.readerоб'єкті, де з map, мені потрібно було __next__явно зателефонувати, щоб отримати списки з csv.reader. 2) Куди flatMapзаходить? Просто дзвінок mapPartitionsодин працював на мене.
Гален Лонг

1
rdd.mapPartitions(lambda x: csv.reader(x))працює, тому що mapPartitionsочікує Iterableоб’єкт. Якщо ви хочете бути явним, ви можете зрозуміти або висловити генератор. mapпоодинці не працює, тому що не перебирає об’єкт. Звідси моя пропозиція скористатися, flatMap(lambda x: csv.reader([x]))яка буде перебирати читача. Але mapPartitionsтут набагато краще.
нуль323

1
зауважте, що це заголовок буде читатися як рядок даних, а не як заголовок
muon

7

Це в PYSPARK

path="Your file path with file name"

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

Потім ви можете перевірити

df.show(5)
df.count()

6

Якщо ви хочете завантажити csv як кадр даних, ви можете зробити наступне:

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

Це добре працювало для мене.


@GalenLong, якщо ви не проти, чи можете ви поділитися вже існуючою відповіддю
Джеріл,

Дивно, клянусь, була ще одна відповідь на це рішення. Можливо, я заплутався в іншому питанні. Моє ліжко.
Гален Лонг

5

Це відповідає тому, що JP Mercier спочатку пропонував використовувати Pandas, але з суттєвою модифікацією: Якщо ви читаєте дані в Pandas шматками, це має бути більш корисним. Це означає, що ви можете розібрати значно більший файл, ніж Pandas насправді може обробити як єдиний фрагмент і передати його Spark менших розмірів. (Це також відповідає на коментар про те, чому можна було б використовувати Spark, якщо вони все-таки зможуть завантажити все в Pandas.)

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

Тепер також є інший варіант для будь-якого загального файлу CSV: https://github.com/seahboonsiew/pyspark-csv наступним чином:

Припустимо, у нас такий контекст

sc = SparkContext
sqlCtx = SQLContext or HiveContext

Спочатку розповсюдьте pyspark-csv.py виконавцям за допомогою SparkContext

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

Читайте дані csv через SparkContext і конвертуйте їх у DataFrame

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

3

Якщо ваші дані CSV не містять нових рядків у жодному з полів, ви можете завантажити свої дані textFile()та проаналізувати їх

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

Якщо у вас є будь-який ряд або кілька рядків із меншою чи більшою кількістю стовпців, ніж 2 у наборі даних, ця помилка може виникнути.

Я також новачок у Pyspark і намагаюся прочитати файл CSV. Наступний код працював для мене:

У цьому коді я використовую набір даних з kaggle посилання: https://www.kaggle.com/carrie1/ecommerce-data

1. Не згадуючи схему:

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

Тепер перевірте стовпці: sdfData.column

Вихід буде:

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

Перевірте тип даних для кожного стовпця:

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

Це дасть кадр даних з усіма стовпцями з типом даних як StringType

2. За допомогою схеми: Якщо ви знаєте схему або хочете змінити тип даних будь-якого стовпця у наведеній вище таблиці, використовуйте це (скажімо, у мене є наступні стовпці та хочу їх у певному типі даних для кожного з них)

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)

Тепер перевірте схему типу даних кожного стовпця:

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

Відредаговано: Ми також можемо використовувати наступний рядок коду, не чітко згадуючи схему:

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

Вихід:

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

Вихід буде виглядати приблизно так:

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

Під час використання spark.read.csvя вважаю, що використовуючи параметри escape='"'та multiLine=Trueпропонуючи найбільш послідовне рішення стандарту CSV , і на мій досвід найкраще працює з файлами CSV, експортованими з Google Таблиць.

Це є,

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

звідки береться іскра? це import pyspark as spark?
Лук Арон

@LukAron У оболонці Pyspark sparkвже ініціалізовано. У сценарії, поданому користувачем spark-submit, ви можете створити його як from pyspark.sql import SparkSession; spark = SparkSession.builder.getOrCreate().
flow2k
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.