J'essaie de comprendre pourquoi cela échoue, même si la documentation dit:

dropna: booléen, facultatif Supprimez les valeurs manquantes des données avant de tracer.

from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
sns.__version__
# '0.7.dev'
# generate an example DataFrame
a = pd.DataFrame(data={
    'a': np.random.normal(size=(100,)),
    'b': np.random.lognormal(size=(100,)),
    'c': np.random.exponential(size=(100,))})
sns.pairplot(a) # this works as expected
# snip
b = a.copy()
b.iloc[5,2] = np.nan # replace one value in col 'c' by a NaN
sns.pairplot(b) # this fails with error 
                # "AttributeError: max must be larger than min in range parameter."
                # in histogram(a, bins, range, normed, weights, density)"
> sns.pairplot(b, dropna=True) # same error as above
7
Diziet Asahi 18 juil. 2015 à 19:58

2 réponses

Meilleure réponse

Je vais poster une réponse à ma propre question, même si cela ne résout pas exactement le problème en général, mais au moins cela résout mon problème.

Le problème se pose lorsque vous essayez de dessiner des histogrammes. Cependant, il semble que les kde soient beaucoup plus robustes aux données manquantes. Par conséquent, cela fonctionne, malgré le NaN au milieu de la trame de données:

from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
sns.__version__
# '0.7.dev'
# generate an example DataFrame
a = pd.DataFrame(data={
    'a': np.random.normal(size=(100,)),
    'b': np.random.lognormal(size=(100,)),
    'c': np.random.exponential(size=(100,))})
a.iloc[5,2] = np.nan # replace one value in col 'c' by a NaN
sns.pairplot(a, diag_kind='kde')
3
Diziet Asahi 13 janv. 2017 à 14:38

Quelque chose de nécro- mais comme j'ai trouvé la réponse à cela aujourd'hui, j'ai pensé que ça valait la peine d'être partagé. Je n'ai pas pu trouver cette solution ailleurs sur le web ... Si le mot-clé Seaborn ignoreNa n'a pas fonctionné pour vos données et que vous ne souhaitez pas supprimer toutes les lignes contenant du NaN. Cela devrait fonctionner pour vous.

Tout cela est dans Seaborn 0.9 avec pandas 0.23.4, en supposant une trame de données (df) avec j lignes (échantillons) qui ont n colonnes (attributs).

La solution au problème de Seaborn étant incapable de faire face aux tableaux NaN qui lui sont transmis; en particulier lorsque vous voulez vous assurer de conserver une ligne car elle contient d'autres données utiles, est basée sur l'utilisation d'une fonction pour intercepter les colonnes par paire avant qu'elles ne soient transmises au PairGrid pour le traçage.

Des fonctions peuvent être transmises aux secteurs du réseau pour effectuer une opération par sous-parcelle. Un exemple simple serait de calculer et d'annoter RMSE pour une paire de colonnes (sous-tracé) sur chaque tracé:

def rmse(x,y, **kwargs):
    rmse = math.sqrt(skm.mean_squared_error(x, y))

    label = 'RMSE = ' + str(round(rmse, 2))  
    ax = plt.gca()
    ax.annotate(label, xy = (0.1, 0.95), size = 20, xycoords = ax.transAxes)

grid = grid.map_upper(rmse)

Par conséquent, en écrivant une fonction que Seaborn peut prendre comme argument de traçage des données, qui supprime les NaN sur une paire de colonnes lorsque l'itération grid.map_ sur la trame de données principale, nous pouvons minimiser la perte de données par échantillon (ligne). Cela est dû au fait qu'un NaN consécutif n'entraînera pas la perte de la ligne entière pour toutes les sous-parcelles. Mais plutôt, le sous-tracé de cette paire de colonnes spécifique exclura la ligne donnée.

La fonction suivante effectue la goutte NaN par paire, retourne les deux séries que seaborn trace ensuite sur les axes avec le nuage de points matplotlibs:

df = [YOUR DF HERE]

def col_nan_scatter(x,y, **kwargs):
    df = pd.DataFrame({'x':x[:],'y':y[:]})
    df = df.dropna()
    x = df['x']
    y = df['y']
    plt.gca()
    plt.scatter(x,y)  

cols = df.columns
grid = sns.PairGrid(data= df, vars = cols, height = 4)
grid = grid.map_upper(col_nan_scatter)

La même chose peut être faite avec le tracé seaborn (avec par exemple, juste la valeur x):

def col_nan_kde_histo(x, **kwargs):
    df = pd.DataFrame({'x':x[:]})
    df = df.dropna()
    x = df['x']
    plt.gca()
    sns.kdeplot(x)

cols = df.columns
grid = sns.PairGrid(data= df, vars = cols, height = 4)
grid = grid.map_upper(col_nan_scatter)
grid = grid.map_upper(col_nan_kde_histo)
1
Tom Dowling 13 déc. 2018 à 17:55