web-dev-qa-db-fra.com

Comment "sélectionner négativement" les colonnes dans le cadre de données de Spark

Je ne peux pas le comprendre, mais devinez que c'est simple. J'ai un spark dataframe df. Ce df a des colonnes "A", "B" et "C". Maintenant, disons que j'ai un tableau contenant le nom des colonnes de ce df:

column_names = Array("A","B","C")

Je voudrais faire une df.select() de telle manière que je puisse spécifier quelles colonnes pas sélectionner. Exemple: disons que je ne veux pas sélectionner les colonnes "B". j'ai essayé

df.select(column_names.filter(_!="B"))

mais cela ne fonctionne pas, car

org.Apache.spark.sql.DataFrame ne peut pas être appliqué à (Array [String])

Donc, ici il dit qu'il devrait plutôt fonctionner avec un Seq. Cependant, en essayant

df.select(column_names.filter(_!="B").toSeq)

résulte en

org.Apache.spark.sql.DataFrame ne peut pas être appliqué à (Seq [String]).

Qu'est-ce que je fais mal?

19
Blaubaer

Depuis Spark 1.4 vous pouvez utiliser la méthode drop :

Scala :

case class Point(x: Int, y: Int)
val df = sqlContext.createDataFrame(Point(0, 0) :: Point(1, 2) :: Nil)
df.drop("y")

Python :

df = sc.parallelize([(0, 0), (1, 2)]).toDF(["x", "y"])
df.drop("y")
## DataFrame[x: bigint]
36
zero323

J'ai eu le même problème et l'ai résolu de cette façon (oaffdf est une trame de données):

val dropColNames = Seq("col7","col121")
val featColNames = oaffdf.columns.diff(dropColNames)
val featCols = featColNames.map(cn => org.Apache.spark.sql.functions.col(cn))
val featsdf = oaffdf.select(featCols: _*)

https://forums.databricks.com/questions/2808/select-dataframe-columns-from-a-sequence-of-string.html

8
Edi Bice

OK, c'est moche, mais cette rapide spark session Shell montre quelque chose qui fonctionne:

scala> val myRDD = sc.parallelize(List.range(1,10))
myRDD: org.Apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[17] at parallelize at <console>:21

scala> val myDF = myRDD.toDF("a")
myDF: org.Apache.spark.sql.DataFrame = [a: int]

scala> val myOtherRDD = sc.parallelize(List.range(1,10))
myOtherRDD: org.Apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[20] at parallelize at <console>:21

scala> val myotherDF = myRDD.toDF("b")
myotherDF: org.Apache.spark.sql.DataFrame = [b: int]

scala> myDF.unionAll(myotherDF)
res2: org.Apache.spark.sql.DataFrame = [a: int]

scala> myDF.join(myotherDF)
res3: org.Apache.spark.sql.DataFrame = [a: int, b: int]

scala> val twocol = myDF.join(myotherDF)
twocol: org.Apache.spark.sql.DataFrame = [a: int, b: int]

scala> val cols = Array("a", "b")
cols: Array[String] = Array(a, b)

scala> val selectedCols = cols.filter(_!="b")
selectedCols: Array[String] = Array(a)

scala> twocol.select(selectedCols.head, selectedCols.tail: _*)
res4: org.Apache.spark.sql.DataFrame = [a: int]

Fournir des varargs à une fonction qui en requiert une est traité dans autrequestions SO . La signature de select est là pour garantir que votre liste de colonnes sélectionnées n'est pas vide - ce qui rend la conversion de la liste des colonnes sélectionnées en varargs un peu plus complexe.

5
huitseeker
val columns = Seq("A","B","C")

df.select(columns.diff(Seq("B")))
1
oluies

Dans pyspark, vous pouvez faire

df.select(list(set(df.columns) - set(["B"])))

En utilisant plus d'une ligne, vous pouvez également faire

cols = df.columns
cols.remove("B")
df.select(cols)
1
asmaier

Sera possible de le faire via [SPARK-12139] Spécification de colonne REGEX pour les requêtes Hive

https://issues.Apache.org/jira/browse/SPARK-12139

0
Tagar