Mittelwert, Nanomittel und Warnung: Mittelwert der leeren Scheibe

73

Angenommen, ich konstruiere zwei Numpy-Arrays:

a = np.array([np.NaN, np.NaN])
b = np.array([np.NaN, np.NaN, 3])

Jetzt finde ich, dass np.meandas nanfür beide zurückkehrt aund b:

>>> np.mean(a)
nan
>>> np.mean(b)
nan

Seit numpy 1.8 (veröffentlicht am 20. April 2016) sind wir mit nanmean gesegnet , das nanWerte ignoriert :

>>> np.nanmean(b)
3.0

Wenn das Array jedoch nur nan Werte enthält, wird eine Warnung ausgegeben:

>>> np.nanmean(a)
nan
C:\python-3.4.3\lib\site-packages\numpy\lib\nanfunctions.py:598: RuntimeWarning: Mean of empty slice
  warnings.warn("Mean of empty slice", RuntimeWarning)

Ich mag es nicht, Warnungen zu unterdrücken. Gibt es eine bessere Funktion, mit der ich das Verhalten nanmeanohne diese Warnung ermitteln kann?

Michael Currie
quelle
1
Warum ist die Warnung ein Problem?
Padraic Cunningham
22
Ich muss zugeben, die Warnung macht keinen Sinn. Ein vernünftiges Verhalten ist die konsequente Rückkehr nan; die andere, um konsequent eine Ausnahme auszulösen. Eine Warnung ist eine solche Antwort.
Amadan
Was ist falsch daran, Warnungen zu unterdrücken? Sie müssen dies nicht im großen np.nanmeanStil tun - unterdrücken Sie einfach die Warnung, wenn Sie wissen, dass Sie sie für ein Array aller NaNs verwenden könnten.
Ali_m
2
Außerdem müssen Sie nicht darauf achten nanmean- Sie bekommen das gleiche dumme Ding mit np.mean([]).
Amadan
3
Ihre Frage enthielt tatsächlich die Antwort, die ich für die Bedeutung dieser Warnung suchte.
erickrf

Antworten:

65

Ich sehe wirklich keinen guten Grund, die Warnung nicht einfach zu unterdrücken.

Am sichersten ist es, den warnings.catch_warningsKontextmanager zu verwenden, um die Warnung nur dort zu unterdrücken, wo Sie sie erwarten. Auf diese Weise verpassen Sie keine zusätzlichen Warnungen, RuntimeWarningsdie in einem anderen Teil Ihres Codes unerwartet ausgelöst werden könnten:

import numpy as np
import warnings

x = np.ones((1000, 1000)) * np.nan

# I expect to see RuntimeWarnings in this block
with warnings.catch_warnings():
    warnings.simplefilter("ignore", category=RuntimeWarning)
    foo = np.nanmean(x, axis=1)

Die Lösung von @ dawg würde auch funktionieren, aber letztendlich verursachen alle zusätzlichen Schritte, die Sie ausführen müssen, um die Berechnung np.nanmeanauf einem Array aller NaNs zu vermeiden, zusätzlichen Aufwand, den Sie vermeiden könnten, indem Sie nur die Warnung unterdrücken. Auch Ihre Absicht wird sich viel deutlicher im Code widerspiegeln.

ali_m
quelle
4
Dies ist eine nutzlose Warnung und es gibt keine seterrdafür wie andere Fehler
schneidig
2
Sind Sie sicher, dass die einzige Warnung, die hier ausgegeben werden könnte, diese besondere ist? Dies ist der Grund dafür, Warnungen im Allgemeinen nicht zu unterdrücken - was ist, wenn dies eine weitere Warnung auslöst (möglicherweise in einer zukünftigen Version)?
Mr_and_Mrs_D
1
Genau, was @Mr_and_Mrs_D, dies scheint ein guter Weg zu sein, um tatsächliche Fehler im Code zu vertuschen. Numpy sollte wahrscheinlich eine bestimmte Warnung auslösen, dass Unterklassen RuntimeWarning.
naught101
2
Ich bin hierher gekommen, als ich nach dieser Warnung gesucht habe: RuntimeWarning: Mittelwert der leeren Scheibe. In meinem Fall lag es daran, den Mittelwert eines leeren Arrays zu finden. Ich hätte auf die Warnung achten sollen, da dies zu einem NaN-Wert führt, der mir beim Modellbau viel Kummer bereitet hat, sodass die Warnung nicht einfach ignoriert werden sollte.
mudassirkhan19
2
warnings.filterwarnings(action='ignore', message='Mean of empty slice')scheint sicherer zu sein, da andere RuntimeWarning, die Sie nicht erwartet haben, nicht ignoriert werden .
Aaron
16

Ein NaNWert ist so definiert, dass er nicht gleich sich selbst ist:

>>> float('nan') == float('nan')
False
>>> np.NaN == np.NaN
False

Sie können eine Python-Bedingung verwenden und die Eigenschaft eines Nan niemals gleich sein, um dieses Verhalten zu erhalten:

>>> a = np.array([np.NaN, np.NaN])
>>> b = np.array([np.NaN, np.NaN, 3])
>>> np.NaN if np.all(a!=a) else np.nanmean(a)
nan
>>> np.NaN if np.all(b!=b) else np.nanmean(b)
3.0

Sie können auch tun:

import warnings
import numpy as np

a = np.array([np.NaN, np.NaN])
b = np.array([np.NaN, np.NaN, 3])

with warnings.catch_warnings():
    warnings.filterwarnings('error')
    try:
        x=np.nanmean(a)
    except RuntimeWarning:
        x=np.NaN    
print x    
dawg
quelle
Das funktioniert für eindimensionale Numpy-Arrays. Leider habe ich in meinem tatsächlichen Anwendungsfall mehrdimensionale Daten und nehme den Mittelwert entlang einer Dimension. zBnp.nanmean(np.array([[np.NaN], [3]]),1)
Michael Currie
Fügen Sie dann das entsprechende Schneiden hinzu. Auch np.nanmean(np.array([[np.NaN], [3]]),1)scheint wie erwartet zu funktionieren ...
dawg
2
Warum einen try/ exceptBlock verwenden? np.nanmean(a)werde np.nantrotzdem zurückkehren.
Ali_m
Es scheint mir nur eine erwartete Syntax zu sein, dies in einen try / exceptBlock zu setzen , da anderer Python-Code für etwas wäre, das sich von der normalen Rückgabe unterscheiden könnte.
Morgengrauen
Außerdem np.nanwäre die Rückgabe eines Skalars np.nanmeanentlang einer Achse eines mehrdimensionalen Arrays, das nur NaNs enthält, falsch
ali_m