0

Ich habe einen Datenrahmen mit einigen Nullwerten definiert. Einige Spalten sind vollständig Nullwerte.Wie Nullspalte in pyspark zu erkennen ist

>> df.show() 
+---+---+---+----+ 
| A| B| C| D| 
+---+---+---+----+ 
|1.0|4.0|7.0|null| 
|2.0|5.0|7.0|null| 
|3.0|6.0|5.0|null| 
+---+---+---+----+ 

In meinem Fall möchte ich eine Liste der Spalten Namen zurückzugeben, die mit Nullwerten gefüllt sind. Meine Idee war, die konstanten Spalten zu erkennen (da die ganze Spalte den gleichen Nullwert enthält).

das ist, wie ich es tat:

nullCoulumns = [c for c, const in df.select([(min(c) == max(c)).alias(c) for c in df.columns]).first().asDict().items() if const] 

aber dies bedeutet nicht null-Spalten als konstant betrachten, es funktioniert nur mit Werten. Wie soll ich das dann machen?

Antwort

3

Erweitere Bedingung

from pyspark.sql.functions import min, max 

((min(c).isNull() & max(c).isNull()) | (min(c) == max(c))).alias(c) 

oder eqNullSafe (PySpark 2.3) verwenden:

(min(c).eqNullSafe(max(c))).alias(c) 
+1

@desertnaut: Das ist ein ziemlich schneller ist, dauert nur Sekunden DECIM: D –

1

Eine Möglichkeit, dies zu tun wäre implizit: jede Spalte auswählen, seine NULL-Werte zählen, und dann Vergleichen Sie dies mit der Gesamtzahl der Zeilen. Mit Ihrer Daten, dies wäre:

spark.version 
# u'2.2.0' 

from pyspark.sql.functions import col 

nullColumns = [] 
numRows = df.count() 
for k in df.columns: 
    nullRows = df.where(col(k).isNull()).count() 
    if nullRows == numRows: # i.e. if ALL values are NULL 
    nullColumns.append(k) 

nullColumns 
# ['D'] 

Aber es gibt einen einfacheren Weg: es stellt sich heraus, dass die Funktion countDistinct, wenn alle NULL-Werte auf eine Säule aufgetragen, gibt Null (0):

from pyspark.sql.functions import countDistinct 

df.agg(countDistinct(df.D).alias('distinct')).collect() 
# [Row(distinct=0)] 

So ist die for Schleife kann jetzt sein:

nullColumns = [] 
for k in df.columns: 
    if df.agg(countDistinct(df[k])).collect()[0][0] == 0: 
    nullColumns.append(k) 

nullColumns 
# ['D'] 

UPDATE (nach Kommentaren): Es scheint möglich, collect in der zweiten Lösung zu vermeiden; da df.agg gibt einen Datenrahmen mit nur einer Reihe, collect mit take(1) ersetzt wird den Job sicher tun:

nullColumns = [] 
for k in df.columns: 
    if df.agg(countDistinct(df[k])).take(1)[0][0] == 0: 
    nullColumns.append(k) 

nullColumns 
# ['D'] 
+0

@MehdiBenHamida Vorsicht! 'collect' wird hier ** nicht ** auf Ihre gesamten Daten angewendet, sondern auf eine * Aggregation *. Dies ist eine legitime Verwendung von 'collect'. – desertnaut

+0

Ich weiß, dass Sammeln ist über die Aggregation, aber immer noch eine Menge Leistung verbrauchen:/ –

+0

@MehdiBenHamida vielleicht haben Sie nicht erkannt, dass das, was Sie fragen, überhaupt nicht trivial ist: auf die eine oder andere Weise müssen Sie durchgehen * alle * Ihre Zeilen, nach NULLs suchend; jetzt, wenn Sie nicht glücklich sind, sogar 'countDistinct' zu verwenden ... (als ob' min' und 'max' weniger Zeit benötigen würden, wenn anwendbar) – desertnaut