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?
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]
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
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.
val columns = Seq("A","B","C")
df.select(columns.diff(Seq("B")))
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)
Sera possible de le faire via [SPARK-12139] Spécification de colonne REGEX pour les requêtes Hive