根据row_number过滤RDD

时间:2014-11-19 16:34:24

标签: python csv apache-spark

sc.textFile(path)允许读取HDFS文件,但它不接受参数(比如跳过多行,has_headers,......)。

在学习星火" O' Reilly电子书,建议使用以下函数读取CSV(例5-12.Python加载CSV示例)

import csv
import StringIO

def loadRecord(line):
"""Parse a CSV line"""
input = StringIO.StringIO(line)
reader = csv.DictReader(input, fieldnames=["name", "favouriteAnimal"])
return reader.next()
input = sc.textFile(inputFile).map(loadRecord)

我的问题是关于如何选择行"采取":

  1. 如何避免加载第一行(标题)
  2. 如何删除特定行(例如,第5行)
  3. 我在这里看到一些不错的解决方案:select range of elements但我想看看是否有更简单的事情。

    THX!

1 个答案:

答案 0 :(得分:17)

不要担心加载您不需要的行/行。当你这样做时:

input = sc.textFile(inputFile)

您没有加载该文件。您只是获得了一个允许您对文件进行操作的对象。所以为了提高效率,最好只考虑获得你想要的东西。例如:

header = input.take(1)[0]
rows = input.filter(lambda line: line != header)

请注意,这里我没有使用索引来引用我想要删除的行,而是使用它的值。这有副作用,其他具有此值的行也将被忽略,但更符合Spark的精神,因为Spark会在节点的不同部分分发您的文本文件,并且行号的概念在每个分区中都会丢失。这也是为什么在Spark(Hadoop)中不容易做到的原因,因为每个分区都应该被认为是独立的,并且全局行号会打破这个假设。

如果您确实需要使用行号,我建议您将它们添加到Spark之外的文件中(请参阅here),然后只在Spark中按此列进行过滤。

修改:根据@Daniel Darabos的建议添加了zipWithIndex解决方案。

sc.textFile('test.txt')\
  .zipWithIndex()\            # [(u'First', 0), (u'Second', 1), ...
  .filter(lambda x: x[1]!=5)\ # select columns
  .map(lambda x: x[0])\       # [u'First', u'Second'
  .collect()