web-dev-qa-db-ja.com

PySparkドロップ行

pySparkのRDDから行を削除するにはどうすればよいですか?特に最初の行は、データセットに列名が含まれる傾向があるためです。 APIを熟読して、これを行う簡単な方法を見つけることができないようです。もちろん、これはBash/HDFSを介して実行できますが、PySpark内から実行できるかどうかを知りたいだけです。

20
Jack

私の知る限り、これを行うための「簡単な」方法はありません。

ただし、これでうまくいくはずです:

val header = data.first
val rows = data.filter(line => line != header)
18
maasg

PySparkに固有:

@maasgによると、これを行うことができます:

header = rdd.first()
rdd.filter(lambda line: line != header)

ただし、データとヘッダーを含む行を除外する可能性があるため、技術的には正しくありません。しかし、これは私にとってはうまくいくようです:

def remove_header(itr_index, itr):
    return iter(list(itr)[1:]) if itr_index == 0 else itr
rdd.mapPartitionsWithIndex(remove_header)

同様に:

rdd.zipWithIndex().filter(lambda tup: tup[1] > 0).map(lambda tup: tup[0])

私はSparkが初めてなので、どちらが最速になるかについて知的にコメントすることはできません。

20
user4081921

Python 3:を使用している場合、

noHeaderRDD = rawRDD.zipWithIndex().filter(lambda row_index: row_index[1] > 0).keys()
5
noleto

私はさまざまなソリューションでいくつかのプロファイリングを行い、次のものを持っています

クラスター構成

クラスター

  • クラスター1:4コア16 GB
  • クラスター2:4コア16 GB
  • クラスター3:4コア16 GB
  • クラスター4:2コア8 GB

データ

700万行、4列

#Solution 1
# Time Taken : 40 ms
data=sc.TextFile('file1.txt')
firstRow=data.first()
data=data.filter(lambda row:row != firstRow)

#Solution 2
# Time Taken : 3 seconds
data=sc.TextFile('file1.txt')
def dropFirstRow(index,iterator):
     return iter(list(iterator)[1:]) if index==0 else iterator
data=data.mapPartitionsWithIndex(dropFirstRow)

#Solution 3
# Time Taken : 0.3 seconds
data=sc.TextFile('file1.txt')
def dropFirstRow(index,iterator):
     if(index==0):
          for subIndex,item in enumerate(iterator):
               if subIndex > 0:
                    yield item
     else:
          yield iterator

data=data.mapPartitionsWithIndex(dropFirstRow)

ソリューション3は最もスケーラブルだと思います

2
Anant Gupta

Spark2.1でテストしました。ファイルの列数を知らずに最初の14行を削除するとします。

sc = spark.sparkContext
lines = sc.textFile("s3://location_of_csv")
parts = lines.map(lambda l: l.split(","))
parts.zipWithIndex().filter(lambda tup: tup[1] > 14).map(lambda x:x[0])

withColumnはdf関数です。したがって、上記の場合に使用されるRDDスタイルでは、以下は機能しません。

parts.withColumn("index",monotonically_increasing_id()).filter(index > 14)
1
kartik

個人的には、フィルタを使用してこのようなものを取り除くのが最も簡単な方法だと思います。しかし、あなたのコメントごとに別のアプローチがあります。各パーティションが配列になるようにRDDをグロムし(パーティションごとに1つのファイルがあり、各ファイルの先頭に問題のある行があると仮定します)、最初の要素をスキップします(これはscala api)。

data.glom().map(x => for (elem <- x.drop(1){/*do stuff*/}) //x is an array so just skip the 0th index

RDDの大きな特徴の1つは不変であるということです。そのため、行を自然に削除することは難しいことです。

PDATE:より良いソリューション。
rdd.mapPartions(x => for (elem <- x.drop(1){/*do stuff*/} )
glomと同じですが、この場合xはイテレータであるため、すべてを配列に入れるオーバーヘッドはありません

1
aaronman