J'ai un pd.DataFrame qui a été créé en analysant des feuilles de calcul Excel. Une colonne dont les cellules sont vides. Par exemple, ci-dessous est la sortie pour la fréquence de cette colonne, les enregistrements 32320 ont des valeurs manquantes pour le locataire.
In [67]: value_counts(Tenant,normalize=False)
Out[67]:
32320
Thunderhead 8170
Big Data Others 5700
Cloud Cruiser 5700
Partnerpedia 5700
Comcast 5700
SDP 5700
Agora 5700
dtype: int64
J'essaie de supprimer des lignes où le locataire est manquant, mais l'option isnull ne reconnaît pas les valeurs manquantes.
In [71]: df['Tenant'].isnull().sum()
Out[71]: 0
La colonne a le type de données "Object". Que se passe-t-il dans ce cas? Comment puis-je supprimer des enregistrements où le locataire est manquant?
Les pandas reconnaîtront une valeur comme nulle s'il s'agit d'un objet np.nan
, qui s'imprimera sous la forme NaN
dans le DataFrame. Vos valeurs manquantes sont probablement des chaînes vides que Pandas ne reconnaît pas comme nulles. Pour résoudre ce problème, vous pouvez convertir les objets vides (ou le contenu de vos cellules vides) en objets np.nan
à l'aide de replace()
, puis appeler dropna()
sur votre DataFrame pour supprimer les lignes avec des locataires nuls.
Pour démontrer, nous créons un DataFrame avec des valeurs aléatoires et des chaînes vides dans une colonne Tenants
:
>>> import pandas as pd
>>> import numpy as np
>>>
>>> df = pd.DataFrame(np.random.randn(10, 2), columns=list('AB'))
>>> df['Tenant'] = np.random.choice(['Babar', 'Rataxes', ''], 10)
>>> print df
A B Tenant
0 -0.588412 -1.179306 Babar
1 -0.008562 0.725239
2 0.282146 0.421721 Rataxes
3 0.627611 -0.661126 Babar
4 0.805304 -0.834214
5 -0.514568 1.890647 Babar
6 -1.188436 0.294792 Rataxes
7 1.471766 -0.267807 Babar
8 -1.730745 1.358165 Rataxes
9 0.066946 0.375640
Nous remplaçons maintenant les chaînes vides de la colonne Tenants
par les objets np.nan
, comme suit:
>>> df['Tenant'].replace('', np.nan, inplace=True)
>>> print df
A B Tenant
0 -0.588412 -1.179306 Babar
1 -0.008562 0.725239 NaN
2 0.282146 0.421721 Rataxes
3 0.627611 -0.661126 Babar
4 0.805304 -0.834214 NaN
5 -0.514568 1.890647 Babar
6 -1.188436 0.294792 Rataxes
7 1.471766 -0.267807 Babar
8 -1.730745 1.358165 Rataxes
9 0.066946 0.375640 NaN
Nous pouvons maintenant supprimer les valeurs NULL:
>>> df.dropna(subset=['Tenant'], inplace=True)
>>> print df
A B Tenant
0 -0.588412 -1.179306 Babar
2 0.282146 0.421721 Rataxes
3 0.627611 -0.661126 Babar
5 -0.514568 1.890647 Babar
6 -1.188436 0.294792 Rataxes
7 1.471766 -0.267807 Babar
8 -1.730745 1.358165 Rataxes
value_counts omet NaN par défaut, vous avez donc probablement affaire à "".
Donc, vous pouvez simplement les filtrer comme
filter = df["Tenant"] != ""
dfNew = df[filter]
il y a une situation où la cellule a un espace blanc, vous ne pouvez pas le voir, utilisez
df['col'].replace(' ', np.nan, inplace=True)
remplacer l'espace blanc par NaN,
ensuite
df= df.dropna(subset=['col'])
df[df['col'].astype(bool)]
Les chaînes vides sont faussaires, ce qui signifie que vous pouvez filtrer les valeurs booléennes comme ceci:
df = pd.DataFrame({
'A': range(5),
'B': ['foo', '', 'bar', '', 'xyz']
})
df
A B
0 0 foo
1 1
2 2 bar
3 3
4 4 xyz
df['B'].astype(bool)
0 True
1 False
2 True
3 False
4 True
Name: B, dtype: bool
df[df['B'].astype(bool)]
A B
0 0 foo
2 2 bar
4 4 xyz
Si votre objectif est de supprimer non seulement les chaînes vides, mais également les chaînes ne contenant que des espaces, utilisez str.strip
auparavant:
df[df['B'].str.strip().astype(bool)]
A B
0 0 foo
2 2 bar
4 4 xyz
.astype
est une opération vectorisée, plus rapide que toutes les options présentées jusqu'à présent. Du moins d'après mes tests. YMMV.
Voici une comparaison de temps, j'ai jeté dans d'autres méthodes que je pourrais penser.
Code de référence, pour référence:
import pandas as pd
import perfplot
df1 = pd.DataFrame({
'A': range(5),
'B': ['foo', '', 'bar', '', 'xyz']
})
perfplot.show(
setup=lambda n: pd.concat([df1] * n, ignore_index=True),
kernels=[
lambda df: df[df['B'].astype(bool)],
lambda df: df[df['B'] != ''],
lambda df: df[df['B'].replace('', np.nan).notna()], # optimized 1-col
lambda df: df.replace({'B': {'': np.nan}}).dropna(subset=['B']),
],
labels=['astype', "!= ''", "replace + notna", "replace + dropna", ],
n_range=[2**k for k in range(1, 15)],
xlabel='N',
logx=True,
logy=True,
equality_check=pd.DataFrame.equals)
Vous pouvez utiliser cette variante:
import pandas as pd
vals = {
'name' : ['n1', 'n2', 'n3', 'n4', 'n5', 'n6', 'n7'],
'gender' : ['m', 'f', 'f', 'f', 'f', 'c', 'c'],
'age' : [39, 12, 27, 13, 36, 29, 10],
'education' : ['ma', None, 'school', None, 'ba', None, None]
}
df_vals = pd.DataFrame(vals) #converting dict to dataframe
Cela produira (** - mettant en évidence uniquement les lignes souhaitées):
age education gender name
0 39 ma m n1 **
1 12 None f n2
2 27 school f n3 **
3 13 None f n4
4 36 ba f n5 **
5 29 None c n6
6 10 None c n7
Donc, pour supprimer tout ce qui n'a pas de valeur 'éducation', utilisez le code ci-dessous:
df_vals = df_vals[~df_vals['education'].isnull()]
('~' indiquant NON)
Résultat:
age education gender name
0 39 ma m n1
2 27 school f n3
4 36 ba f n5