52 votes

Comment filtrer une valeur nulle d'un DataFrame Spark

J'ai créé un dataframe dans spark avec le schéma suivant :

root
 |-- user_id: long (nullable = false)
 |-- event_id: long (nullable = false)
 |-- invited: integer (nullable = false)
 |-- day_diff: long (nullable = true)
 |-- interested: integer (nullable = false)
 |-- event_owner: long (nullable = false)
 |-- friend_id: long (nullable = false)

Et les données sont affichées ci-dessous :

+----------+----------+-------+--------+----------+-----------+---------+
|   user_id|  event_id|invited|day_diff|interested|event_owner|friend_id|
+----------+----------+-------+--------+----------+-----------+---------+
|   4236494| 110357109|      0|      -1|         0|  937597069|     null|
|  78065188| 498404626|      0|       0|         0| 2904922087|     null|
| 282487230|2520855981|      0|      28|         0| 3749735525|     null|
| 335269852|1641491432|      0|       2|         0| 1490350911|     null|
| 437050836|1238456614|      0|       2|         0|  991277599|     null|
| 447244169|2095085551|      0|      -1|         0| 1579858878|     null|
| 516353916|1076364848|      0|       3|         1| 3597645735|     null|
| 528218683|1151525474|      0|       1|         0| 3433080956|     null|
| 531967718|3632072502|      0|       1|         0| 3863085861|     null|
| 627948360|2823119321|      0|       0|         0| 4092665803|     null|
| 811791433|3513954032|      0|       2|         0|  415464198|     null|
| 830686203|  99027353|      0|       0|         0| 3549822604|     null|
|1008893291|1115453150|      0|       2|         0| 2245155244|     null|
|1239364869|2824096896|      0|       2|         1| 2579294650|     null|
|1287950172|1076364848|      0|       0|         0| 3597645735|     null|
|1345896548|2658555390|      0|       1|         0| 2025118823|     null|
|1354205322|2564682277|      0|       3|         0| 2563033185|     null|
|1408344828|1255629030|      0|      -1|         1|  804901063|     null|
|1452633375|1334001859|      0|       4|         0| 1488588320|     null|
|1625052108|3297535757|      0|       3|         0| 1972598895|     null|
+----------+----------+-------+--------+----------+-----------+---------+

Je veux filtrer les lignes qui ont des valeurs nulles dans le champ "friend_id".

scala> val aaa = test.filter("friend_id is null")

scala> aaa.count

J'ai obtenu :res52: Long = 0 ce qui n'est évidemment pas correct. Quelle est la bonne méthode pour l'obtenir ?

Une autre question, je veux remplacer les valeurs dans le champ friend_id. Je veux remplacer null par 0 et 1 pour toute autre valeur sauf null. Le code que je peux trouver est :

val aaa = train_friend_join.select($"user_id", $"event_id", $"invited", $"day_diff", $"interested", $"event_owner", ($"friend_id" != null)?1:0)

Ce code ne fonctionne pas non plus. Quelqu'un peut-il me dire comment je peux le corriger ? Merci

62voto

Sachin Tyagi Points 1661

Disons que vous avez cette configuration de données (pour que les résultats soient reproductibles) :

// déclaration des types de données
case class Company(cName: String, cId: String, details: String)
case class Employee(name: String, id: String, email: String, company: Company)

// configuration des données d'exemple
val e1 = Employee("n1", null, "n1@c1.com", Company("c1", "1", "d1"))
val e2 = Employee("n2", "2", "n2@c1.com", Company("c1", "1", "d1"))
val e3 = Employee("n3", "3", "n3@c1.com", Company("c1", "1", "d1"))
val e4 = Employee("n4", "4", "n4@c2.com", Company("c2", "2", "d2"))
val e5 = Employee("n5", null, "n5@c2.com", Company("c2", "2", "d2"))
val e6 = Employee("n6", "6", "n6@c2.com", Company("c2", "2", "d2"))
val e7 = Employee("n7", "7", "n7@c3.com", Company("c3", "3", "d3"))
val e8 = Employee("n8", "8", "n8@c3.com", Company("c3", "3", "d3"))
val employees = Seq(e1, e2, e3, e4, e5, e6, e7, e8)
val df = sc.parallelize(employees).toDF

Les données sont :

+----+----+---------+---------+
|name|  id|    email|  company|
+----+----+---------+---------+
|  n1|null|n1@c1.com|[c1,1,d1]|
|  n2|   2|n2@c1.com|[c1,1,d1]|
|  n3|   3|n3@c1.com|[c1,1,d1]|
|  n4|   4|n4@c2.com|[c2,2,d2]|
|  n5|null|n5@c2.com|[c2,2,d2]|
|  n6|   6|n6@c2.com|[c2,2,d2]|
|  n7|   7|n7@c3.com|[c3,3,d3]|
|  n8|   8|n8@c3.com|[c3,3,d3]|
+----+----+---------+---------+

Maintenant, pour filtrer les employés avec des null ids, vous ferez :

df.filter("id is null").show

qui vous montrera correctement ce qui suit :

+----+----+---------+---------+
|name|  id|    email|  company|
+----+----+---------+---------+
|  n1|null|n1@c1.com|[c1,1,d1]|
|  n5|null|n5@c2.com|[c2,2,d2]|
+----+----+---------+---------+

Passons à la deuxième partie de votre question, vous pouvez remplacer les ids null par 0 et les autres valeurs par 1 avec ceci :

df.withColumn("id", when($"id".isNull, 0).otherwise(1)).show

Cela donne :

+----+---+---------+---------+
|name| id|    email|  company|
+----+---+---------+---------+
|  n1|  0|n1@c1.com|[c1,1,d1]|
|  n2|  1|n2@c1.com|[c1,1,d1]|
|  n3|  1|n3@c1.com|[c1,1,d1]|
|  n4|  1|n4@c2.com|[c2,2,d2]|
|  n5|  0|n5@c2.com|[c2,2,d2]|
|  n6|  1|n6@c2.com|[c2,2,d2]|
|  n7|  1|n7@c3.com|[c3,3,d3]|
|  n8|  1|n8@c3.com|[c3,3,d3]|
+----+---+---------+---------+

43voto

Adriana Lazar Points 271

Ou comme df.filter($"friend_id".isNotNull)

18voto

Michael Kopaniov Points 740
df.where(df.col("friend_id").isNull)

16voto

chAlexey Points 372

J'ai trouvé une bonne solution pour moi de supprimer les lignes contenant des valeurs nulles :

Dataset filtered = df.filter(row -> !row.anyNull());

Si quelqu'un est intéressé par l'autre cas, il suffit d'appeler row.anyNull(). (Spark 2.1.0 en utilisant l'API Java)

13voto

Ayush Vatsyayan Points 1141

Il y a deux façons de le faire : créer une condition de filtre 1) Manuellement 2) Dynamiquement.

Exemple de DataFrame :

val df = spark.createDataFrame(Seq(
  (0, "a1", "b1", "c1", "d1"),
  (1, "a2", "b2", "c2", "d2"),
  (2, "a3", "b3", null, "d3"),
  (3, "a4", null, "c4", "d4"),
  (4, null, "b5", "c5", "d5")
)).toDF("id", "col1", "col2", "col3", "col4")

+---+----+----+----+----+
| id|col1|col2|col3|col4|
+---+----+----+----+----+
|  0|  a1|  b1|  c1|  d1|
|  1|  a2|  b2|  c2|  d2|
|  2|  a3|  b3|null|  d3|
|  3|  a4|null|  c4|  d4|
|  4|null|  b5|  c5|  d5|
+---+----+----+----+----+

1) Création de la condition de filtre manuellement c'est-à-dire en utilisant la fonction where ou filter du DataFrame

df.filter(col("col1").isNotNull && col("col2").isNotNull).show

ou

df.where("col1 is not null and col2 is not null").show

Résultat :

+---+----+----+----+----+
| id|col1|col2|col3|col4|
+---+----+----+----+----+
|  0|  a1|  b1|  c1|  d1|
|  1|  a2|  b2|  c2|  d2|
|  2|  a3|  b3|null|  d3|
+---+----+----+----+----+

2) Création de la condition de filtre dynamiquement : C'est utile lorsque nous ne voulons pas qu'une colonne contienne une valeur nulle et qu'il y a un grand nombre de colonnes, ce qui est souvent le cas.

Créer la condition de filtre manuellement dans ces cas prendra beaucoup de temps. Dans le code ci-dessous, nous incluons toutes les colonnes dynamiquement en utilisant les fonctions map et reduce sur les colonnes du DataFrame :

val filterCond = df.columns.map(x=>col(x).isNotNull).reduce(_ && _)

À quoi ressemble filterCond :

filterCond: org.apache.spark.sql.Column = (((((id IS NOT NULL) AND (col1 IS NOT NULL)) AND (col2 IS NOT NULL)) AND (col3 IS NOT NULL)) AND (col4 IS NOT NULL))

Filtrage :

val filteredDf = df.filter(filterCond)

Résultat :

+---+----+----+----+----+
| id|col1|col2|col3|col4|
+---+----+----+----+----+
|  0|  a1|  b1|  c1|  d1|
|  1|  a2|  b2|  c2|  d2|
+---+----+----+----+----+

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X