Как пропустить строки при чтении CSV-файла в качестве фрейма данных с помощью PySpark?

у меня есть файл CSV, который структурирован таким образом:

Header
Blank Row
"Col1","Col2"
"1,200","1,456"
"2,000","3,450"

у меня есть две проблемы при чтении этого файла.

  1. Я хочу игнорировать заголовок и игнорировать пустую строку
  2. запятые в значении не являются разделителем

вот что я пробовал:

df = sc.textFile("myFile.csv")
              .map(lambda line: line.split(",")) #Split By comma
              .filter(lambda line: len(line) == 2).collect() #This helped me ignore the first two rows

однако это не сработало, потому что запятые внутри значения считывались как разделитель и len(line) возвращалось 4 вместо 2.

я попробовал другой подход:

data = sc.textFile("myFile.csv")
headers = data.take(2) #First two rows to be skipped

идея заключалась в том, чтобы использовать фильтр и не читать заголовки. Но, когда я попытался распечатать заголовки, я получил закодированные значения.

[x00Ax00Yx00 x00Jx00ux00lx00yx00 x002x000x001x006x00]

Как правильно читать CSV-файл и пропустить первые две строки?

5 ответов


попробуйте использовать csv.читатель с параметром 'quotechar'.Он разделит линию правильно. После этого вы можете добавить фильтры, как вам нравится.

import csv
from pyspark.sql.types import StringType

df = sc.textFile("test2.csv")\
           .mapPartitions(lambda line: csv.reader(line,delimiter=',', quotechar='"')).filter(lambda line: len(line)>=2 and line[0]!= 'Col1')\
           .toDF(['Col1','Col2'])

для вашей первой проблемы просто застегните строки в RDD с zipWithIndex и отфильтровать строки, которые вы не хотите. Для второй проблемы вы можете попытаться удалить первый и последний символы двойной кавычки из строк, а затем разделить строку на ",".

rdd = sc.textFile("myfile.csv")
rdd.zipWithIndex().
    filter(lambda x: x[1] > 2).
    map(lambda x: x[0]).
    map(lambda x: x.strip('"').split('","')).
    toDF(["Col1", "Col2"])

хотя, если вы ищете стандартный способ борьбы с CSV-файлами в Spark, лучше использовать spark-csv пакет из databricks.


если структура файла CSV всегда имеет два столбца, на Scala можно реализовать:

val struct = StructType(
  StructField("firstCol", StringType, nullable = true) ::
  StructField("secondCol", StringType, nullable = true) :: Nil)

val df = sqlContext.read
  .format("com.databricks.spark.csv")
  .option("header", "false")
  .option("inferSchema", "false")
  .option("delimiter", ",")
  .option("quote", "\"")
  .schema(struct)
  .load("myFile.csv")

df.show(false)

val indexed = df.withColumn("index", monotonicallyIncreasingId())
val filtered = indexed.filter(col("index") > 2).drop("index")

filtered.show(false)

результат:

+---------+---------+
|firstCol |secondCol|
+---------+---------+
|Header   |null     |
|Blank Row|null     |
|Col1     |Col2     |
|1,200    |1,456    |
|2,000    |3,450    |
+---------+---------+

+--------+---------+
|firstCol|secondCol|
+--------+---------+
|1,200   |1,456    |
|2,000   |3,450    |
+--------+---------+

почему бы вам просто не попробовать DataFrameReader API от pyspark.sql? Это довольно просто. Для этой проблемы, я думаю, эта единственная строка будет достаточно хороша.

df = spark.read.csv("myFile.csv") # By default, quote char is " and separator is ','

С помощью этого API вы также можете играть с несколькими другими параметрами, такими как строки заголовка, игнорируя ведущие и конечные пробелы. Вот ссылка: API DataFrameReader


ответ Злидиме имел правильную идею. Рабочее решение таково:

import csv

customSchema = StructType([ \
    StructField("Col1", StringType(), True), \
    StructField("Col2", StringType(), True)])

df = sc.textFile("file.csv")\
        .mapPartitions(lambda partition: csv.reader([line.replace('','') for line in partition],delimiter=',', quotechar='"')).filter(lambda line: len(line) > 2 and line[0] != 'Col1')\
        .toDF(customSchema)