Как пропустить строки при чтении CSV-файла в качестве фрейма данных с помощью PySpark?
у меня есть файл CSV, который структурирован таким образом:
Header
Blank Row
"Col1","Col2"
"1,200","1,456"
"2,000","3,450"
у меня есть две проблемы при чтении этого файла.
- Я хочу игнорировать заголовок и игнорировать пустую строку
- запятые в значении не являются разделителем
вот что я пробовал:
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)