comment supprimer des lignes d'un RDD dans PySpark? En particulier la première ligne, car elle a tendance à contenir des noms de colonnes dans mes ensembles de données. En parcourant l'API, je n'arrive pas à trouver un moyen facile de le faire. Bien sûr, je pourrais le faire via Bash/HDFS, mais je veux juste savoir si cela peut être fait à partir de PySpark.
AFAIK, il n'y a pas de moyen "facile" de le faire.
Cela devrait faire l'affaire, cependant:
val header = data.first
val rows = data.filter(line => line != header)
Spécifique à PySpark:
Selon @maasg, vous pouvez faire ceci:
header = rdd.first()
rdd.filter(lambda line: line != header)
mais ce n'est pas techniquement correct, car il est possible d'exclure des lignes contenant des données ainsi que l'en-tête. Cependant, cela semble fonctionner pour moi:
def remove_header(itr_index, itr):
return iter(list(itr)[1:]) if itr_index == 0 else itr
rdd.mapPartitionsWithIndex(remove_header)
De même:
rdd.zipWithIndex().filter(lambda tup: tup[1] > 0).map(lambda tup: tup[0])
Je suis nouveau sur Spark, je ne peux donc pas commenter intelligemment lequel sera le plus rapide.
Un moyen simple d'y parvenir dans PySpark (API Python), en supposant que vous utilisez Python 3:
noHeaderRDD = rawRDD.zipWithIndex().filter(lambda row_index: row_index[1] > 0).keys()
J'ai fait du profilage avec différentes solutions et j'ai les éléments suivants
Configuration de cluster
7 millions de lignes, 4 colonnes
#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)
Je pense que la solution 3 est la plus évolutive
J'ai testé avec spark2.1. Supposons que vous souhaitiez supprimer les 14 premières lignes sans connaître le nombre de colonnes du fichier.
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 est une fonction df. Donc, ci-dessous ne fonctionnera pas dans le style RDD comme utilisé dans le cas ci-dessus.
parts.withColumn("index",monotonically_increasing_id()).filter(index > 14)
Personnellement, je pense que l'utilisation d'un filtre pour se débarrasser de ces trucs est le moyen le plus simple. Mais selon votre commentaire, j'ai une autre approche. Glom le RDD pour que chaque partition soit un tableau (je suppose que vous avez 1 fichier par partition, et chaque fichier a la ligne incriminée en haut), puis sautez simplement le premier élément (c'est avec le scala api).
data.glom().map(x => for (elem <- x.drop(1){/*do stuff*/}) //x is an array so just skip the 0th index
Gardez à l'esprit que l'une des grandes caractéristiques des RDD est qu'ils sont immuables, donc supprimer naturellement une ligne est une chose délicate à faire
MISE À JOUR: Meilleure solution.rdd.mapPartions(x => for (elem <- x.drop(1){/*do stuff*/} )
Identique au glom mais n'a pas la surcharge de tout mettre dans un tableau, car x est un itérateur dans ce cas