web-dev-qa-db-ja.com

PySparkを使用してCSVファイルをdataFrameとして読み取るときに行をスキップするにはどうすればよいですか?

このように構成されたCSVファイルがあります。

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

このファイルの読み取りには2つの問題があります。

  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)が2ではなく4を返していたため、これは機能しませんでした。

私は別のアプローチを試みました:

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

その考えは、フィルターを使用し、ヘッダーを読み取らないことでした。しかし、ヘッダーを印刷しようとすると、エンコードされた値が得られました。

_[\x00A\x00Y\x00 \x00J\x00u\x00l\x00y\x00 \x002\x000\x001\x006\x00]
_

CSVファイルを読み取り、最初の2行をスキップする正しい方法は何ですか?

9

Zlidimeの回答には正しい考えがありました。実用的なソリューションはこれです:

import csv

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

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

'quotechar'パラメーターを指定してcsv.readerを使用してみてください。行が正しく分割されます。その後、必要に応じてフィルターを追加できます。

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'])
7
zlidime

最初の問題については、RDD内の行をzipWithIndexで圧縮し、不要な行をフィルター処理するだけです。 2番目の問題については、行から最初と最後の二重引用符文字を削除してから、","で行を分割することができます。

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

ただし、SparkでCSVファイルを処理する標準的な方法を探している場合は、databricksの spark-csv パッケージを使用することをお勧めします。

7
septra

CSVファイル構造に常に2つの列がある場合、on 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    |
+--------+---------+
2
pasha701

pyspark.sqlからDataFrameReader AP​​Iを試してみませんか?とても簡単です。この問題については、この1行で十分だと思います。

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

このAPIを使用すると、ヘッダー行などの他のいくつかのパラメーターをいじって、先頭および末尾の空白を無視することもできます。リンクは次のとおりです。 DataFrameReader API