web-dev-qa-db-fra.com

Remplacement des valeurs vides (espaces) par NaN dans les pandas

Je souhaite rechercher dans un cadre de données Pandas toutes les valeurs contenant des espaces (tout montant arbitraire) et les remplacer par des valeurs NaN.

Des idées pour améliorer cela?

Fondamentalement, je veux transformer ceci:

                   A    B    C
2000-01-01 -0.532681  foo    0
2000-01-02  1.490752  bar    1
2000-01-03 -1.387326  foo    2
2000-01-04  0.814772  baz     
2000-01-05 -0.222552         4
2000-01-06 -1.176781  qux     

Dans ceci:

                   A     B     C
2000-01-01 -0.532681   foo     0
2000-01-02  1.490752   bar     1
2000-01-03 -1.387326   foo     2
2000-01-04  0.814772   baz   NaN
2000-01-05 -0.222552   NaN     4
2000-01-06 -1.176781   qux   NaN

J'ai réussi à le faire avec le code ci-dessous, mais l'homme est-il moche. Ce n'est pas Pythonic et je suis sûr que ce n'est pas l'utilisation la plus efficace des pandas non plus. Je parcourt chaque colonne et effectue un remplacement booléen par rapport à un masque de colonne généré en appliquant une fonction qui effectue une recherche regex de chaque valeur, en faisant correspondre les blancs.

for i in df.columns:
    df[i][df[i].apply(lambda i: True if re.search('^\s*$', str(i)) else False)]=None

Il pourrait être optimisé un peu en ne parcourant que des champs pouvant contenir des chaînes vides:

if df[i].dtype == np.dtype('object')

Mais ce n'est pas vraiment une amélioration

Et finalement, ce code définit les chaînes cibles sur None, ce qui fonctionne avec les fonctions de Pandas telles que fillna(), mais il serait intéressant de compléter si je pouvais insérer une NaN directement au lieu de None.

93
Chris Clark

Je pense que df.replace() fait le travail:

df = pd.DataFrame([
    [-0.532681, 'foo', 0],
    [1.490752, 'bar', 1],
    [-1.387326, 'foo', 2],
    [0.814772, 'baz', ' '],     
    [-0.222552, '   ', 4],
    [-1.176781,  'qux', '  '],         
], columns='A B C'.split(), index=pd.date_range('2000-01-01','2000-01-06'))

print df.replace(r'\s+', np.nan, regex=True)

Produit:

                   A    B   C
2000-01-01 -0.532681  foo   0
2000-01-02  1.490752  bar   1
2000-01-03 -1.387326  foo   2
2000-01-04  0.814772  baz NaN
2000-01-05 -0.222552  NaN   4
2000-01-06 -1.176781  qux NaN

Comme Temak le fait remarquer, utilisez df.replace(r'^\s+$', np.nan, regex=True) si vos données valides contiennent des espaces.

114
patricksurry

Que diriez-vous:

d = d.applymap(lambda x: np.nan if isinstance(x, basestring) and x.isspace() else x)

La fonction applymap applique une fonction à chaque cellule du cadre de données.

30
BrenBarn

Si vous souhaitez remplacer une chaîne vide et que les enregistrements ne contiennent que des espaces, la réponse correcte est: !:

df = df.replace(r'^\s*$', np.nan, regex=True)

La réponse acceptée

df.replace(r'\s+', np.nan, regex=True)

Ne remplace pas une chaîne vide !, vous pouvez vous essayer avec l'exemple donné légèrement mis à jour:

df = pd.DataFrame([
    [-0.532681, 'foo', 0],
    [1.490752, 'bar', 1],
    [-1.387326, 'fo o', 2],
    [0.814772, 'baz', ' '],     
    [-0.222552, '   ', 4],
    [-1.176781,  'qux', ''],         
], columns='A B C'.split(), index=pd.date_range('2000-01-01','2000-01-06'))

Notez également que 'fo o' n'est pas remplacé par Nan, bien qu'il contienne un espace . Notez aussi qu'un simple:

df.replace(r'', np.NaN)

Ne fonctionne pas non plus - essayez-le.

25
Philipp Schwarz

Je vais faire ceci:

df = df.apply(lambda x: x.str.strip()).replace('', np.nan)

ou

df = df.apply(lambda x: x.str.strip() if isinstance(x, str) else x).replace('', np.nan)

Vous pouvez supprimer toutes les chaînes, puis remplacer les chaînes vides par np.nan.

9
Xiaorong Liao

La solution la plus simple:

df = df.replace(r'^\s+$', np.nan, regex=True)
3
Gil Baggio

Si vous exportez les données du fichier CSV, cela peut être aussi simple que cela:

df = pd.read_csv(file_csv, na_values=' ')

Cela créera le bloc de données et remplacera les valeurs vides en tant que Na

2
ibrahim rupawala

Ce n'est pas une solution élégante, mais ce qui semble fonctionner, c’est enregistrer au format XLSX puis à le réimporter. Les autres solutions sur cette page ne fonctionnaient pas pour moi, sans savoir pourquoi.

data.to_Excel(filepath, index=False)
data = pd.read_Excel(filepath)
0
David Kong

vous pouvez également utiliser un filtre pour le faire.

df = PD.DataFrame([
    [-0.532681, 'foo', 0],
    [1.490752, 'bar', 1],
    [-1.387326, 'foo', 2],
    [0.814772, 'baz', ' '],     
    [-0.222552, '   ', 4],
    [-1.176781,  'qux', '  '])
    df[df=='']='nan'
    df=df.astype(float)
0
ERIC

Pour une solution très simple et rapide où vous vérifiez l’égalité par rapport à une valeur unique, vous pouvez utiliser la méthode mask.

df.mask(df == ' ')
0
Ted Petrou

Celles-ci sont toutes proches de la bonne réponse, mais je ne dirais pas que tout résoudrait le problème tout en restant plus lisible pour les autres lecteurs de votre code. Je dirais que cette réponse est une combinaison de Réponse de BrenBarn et du commentaire de tuomasttik ci-dessous/ réponse . La réponse de BrenBarn utilise la variable isspace intégrée, mais ne prend pas en charge la suppression de chaînes vides, comme demandé par OP, et j'aurais tendance à l'attribuer comme cas d'utilisation standard du remplacement de chaînes par null.

Je l'ai réécrit avec .apply pour que vous puissiez l'appeler sur un pd.Series ou un pd.DataFrame.


Python 3:

Pour remplacer des chaînes vides ou des chaînes d'espaces entièrement:

df = df.apply(lambda x: np.nan if isinstance(x, str) and (x.isspace() or not x) else x)

Pour remplacer des chaînes d'espaces entièrement:

df = df.apply(lambda x: np.nan if isinstance(x, str) and x.isspace() else x)

Pour utiliser cela dans Python 2, vous devrez remplacer str par basestring.

Python 2:

Pour remplacer des chaînes vides ou des chaînes d'espaces entièrement:

df = df.apply(lambda x: np.nan if isinstance(x, basestring) and (x.isspace() or not x) else x)

Pour remplacer des chaînes d'espaces entièrement:

df = df.apply(lambda x: np.nan if isinstance(x, basestring) and x.isspace() else x)
0
spen.smith
print(df.isnull().sum()) # check numbers of null value in each column

modifiedDf=df.fillna("NaN") # Replace empty/null values with "NaN"

# modifiedDf = fd.dropna() # Remove rows with empty values

print(modifiedDf.isnull().sum()) # check numbers of null value in each column
0
Jayantha