0
votes

Filtrer les colonnes manquantes au-dessus du seuil dans l'étincelle

Je veux filtrer toutes les colonnes avec des valeurs manquantes supérieures à 90 PCT dans Spark afin que je puisse les supprimer de l'analyse.

J'ai essayé le code suivant, mais cela prend une éternité:

from pyspark.sql.functions import isnull, when, count, col
total_rows = df.count()
features_missing_above_90 = []
    
for feature in df.columns:
    
    feature_nulls = df.filter(df[feature].isNull()).count()
    result = (feature_nulls/total_rows)
    
    if(result>0.9):
        features_missing_above_90.append(df[feature].str)
    
print(features_missing_above_90)

Quelqu'un peut-il m'aider?

Merci!


0 commentaires

3 Réponses :


0
votes

Je pense que vous vouliez ajouter le nom de la colonne à la liste, pas la représentation sous forme de chaîne du dataframe.

total_rows = df.count()
features_missing_above_90 = []
    
for feature in df.columns:    
    feature_nulls = df.filter(df[feature].isNull()).count()
    result = (feature_nulls / total_rows)
    
    if (result > 0.9):
        features_missing_above_90.append(feature)
    
df = df.select([col for col in df.columns if col not in features_missing_above_90])


0 commentaires

0
votes

Remplacez df.count() par une valeur flottante, sans cela, votre condition if ne s'exécutera pas car un entier / entier ne vous donnera qu'un entier.

>>> df \
... .select(F.array(*columns).alias("columns")) \
... .select(F.explode(F.col("columns")).alias("columns")) \
... .select(F.collect_set(F.col("columns")).alias("missing")) \
... .collect()[0]

Row(missing=[u'b', u'e'])
>>> columns = map(lambda c: F.when(((F.count(F.col("*")) - F.size(F.collect_set(F.col(c))))/F.count(F.col("*"))) > F.lit(threshold), F.lit(c)),df.columns)
>>> threshold = 0.7
>>> df.show()
+----+----+----+----+----+----+
|   a|   b|   c|   d|   e|   f|
+----+----+----+----+----+----+
|   1|null|   2|   3|null|   4|
|   2|null|null|   5|null|   6|
|   4|   2|   1|   4|   5|   6|
|   5|null|null|null|null|   4|
|null|null|null|null|null|null|
+----+----+----+----+----+----+

Vous pouvez également essayer le code ci-dessous.

>>> print(features_missing_above_90)
['b', 'e']
>>> for feature in df.columns:
...     feature_nulls = df.filter(F.col(feature).isNull()).count()
...     result = feature_nulls/total_rows
...     if(result>0.7):
...             features_missing_above_90.append(feature)
...

Application de la logique

>>> features_missing_above_90 = []
>>> total_rows = float(df.count())


2 commentaires

Salut, merci pour votre message. Il serait peut-être préférable d'utiliser collect_list au lieu de collect_set dans la fonction map pour traiter les champs catégoriels qui ont des valeurs répétées, étant donné que collect_set ignore les doublons.


Ok, il est difficile d'accéder aux colonnes en double .. si vous avez des colonnes en double dans la trame de données, dites les noms de colonnes a, a .. comment obtenir des valeurs seulement après une colonne ..?



0
votes

Après avoir analysé le code par @Srinivas, j'ai fait quelques modifications mineures à des fins de performances:

threshold = 0.9

columns = map(lambda c: F.when(   ((F.sum(F.col(c).isNull().cast("double"))) / (F.count("*")))    >= F.lit(threshold), F.lit(c)),df.columns)

lst_columns_missing = df \
    .select(F.array(*columns).alias("columns")) \
    .select(F.explode(F.col("columns")).alias("columns")) \
    .select(F.collect_set(F.col("columns")).alias("missing")) \
    .collect()[0]


0 commentaires