J'ai une grande base de données dans pandas), mis à part que la colonne utilisée comme index est supposée avoir uniquement des valeurs numériques:
df = pd.DataFrame({'a': [1, 2, 3, 'bad', 5],
'b': [0.1, 0.2, 0.3, 0.4, 0.5],
'item': ['a', 'b', 'c', 'd', 'e']})
df = df.set_index('item')
Comment trouver la ligne de la dataframe df
contenant une valeur non numérique?
Dans cet exemple, il s’agit de la quatrième ligne du cadre de données, qui contient la chaîne 'bad'
dans la colonne a
. Comment cette ligne peut-elle être trouvée par programme?
Vous pouvez utiliser np.isreal
pour vérifier le type de chaque élément ( applymap applique une fonction à chaque élément du DataFrame):
In [11]: df.applymap(np.isreal)
Out[11]:
a b
item
a True True
b True True
c True True
d False True
e True True
Si tous les éléments de la ligne sont vrais, ils sont tous numériques:
In [12]: df.applymap(np.isreal).all(1)
Out[12]:
item
a True
b True
c True
d False
e True
dtype: bool
Donc, pour obtenir le sous-cadre DataFrame de rouges, (Remarque: la négation, ~, de ce qui précède trouve ceux qui ont au moins un voyou non numérique):
In [13]: df[~df.applymap(np.isreal).all(1)]
Out[13]:
a b
item
d bad 0.4
Vous pouvez également trouver l'emplacement du premier délinquant que vous pouvez utiliser argmin :
In [14]: np.argmin(df.applymap(np.isreal).all(1))
Out[14]: 'd'
Comme @ CTZh fait remarquer, il peut être légèrement plus rapide de vérifier s'il s'agit d'une instance de int ou float (il y a une surcharge supplémentaire avec np.isreal):
df.applymap(lambda x: isinstance(x, (int, float)))
Déjà quelques bonnes réponses à cette question, cependant voici un extrait de Nice que j'utilise régulièrement pour supprimer des lignes si elles ont des valeurs non numériques sur certaines colonnes:
# Eliminate invalid data from dataframe (see Example below for more context)
num_df = (df.drop(data_columns, axis=1)
.join(df[data_columns].apply(pd.to_numeric, errors='coerce')))
num_df = num_df[num_df[data_columns].notnull().all(axis=1)]
La façon dont cela fonctionne est d’abord drop
tous les data_columns
du df
, puis utilisez un join
pour les remettre après les avoir passés par pd.to_numeric
(avec l'option 'coerce'
, de sorte que toutes les entrées non numériques soient converties en NaN
). Le résultat est enregistré sur num_df
.
Sur la deuxième ligne, nous utilisons un filtre qui ne conserve que les lignes où toutes les valeurs ne sont pas nulles.
Notez que pd.to_numeric
contraint NaN
tout ce qui ne peut pas être converti en valeur numérique, ainsi les chaînes représentant des valeurs numériques ne seront pas supprimées. Par exemple '1.25'
sera reconnu comme la valeur numérique 1.25
.
Avertissement: pd.to_numeric
a été introduit dans pandas version 0.17.0
Exemple:
In [1]: import pandas as pd
In [2]: df = pd.DataFrame({"item": ["a", "b", "c", "d", "e"],
...: "a": [1,2,3,"bad",5],
...: "b":[0.1,0.2,0.3,0.4,0.5]})
In [3]: df
Out[3]:
a b item
0 1 0.1 a
1 2 0.2 b
2 3 0.3 c
3 bad 0.4 d
4 5 0.5 e
In [4]: data_columns = ['a', 'b']
In [5]: num_df = (df
...: .drop(data_columns, axis=1)
...: .join(df[data_columns].apply(pd.to_numeric, errors='coerce')))
In [6]: num_df
Out[6]:
item a b
0 a 1 0.1
1 b 2 0.2
2 c 3 0.3
3 d NaN 0.4
4 e 5 0.5
In [7]: num_df[num_df[data_columns].notnull().all(axis=1)]
Out[7]:
item a b
0 a 1 0.1
1 b 2 0.2
2 c 3 0.3
4 e 5 0.5
Désolé pour la confusion, cela devrait être la bonne approche. Voulez-vous seulement capturer 'bad'
seulement, pas des choses comme 'good'
; Ou simplement des valeurs non numériques?
In[15]:
np.where(np.any(np.isnan(df.convert_objects(convert_numeric=True)), axis=1))
Out[15]:
(array([3]),)
# Original code
df = pd.DataFrame({'a': [1, 2, 3, 'bad', 5],
'b': [0.1, 0.2, 0.3, 0.4, 0.5],
'item': ['a', 'b', 'c', 'd', 'e']})
df = df.set_index('item')
Convertir en numérique en utilisant 'coerce' qui remplit les mauvaises valeurs avec 'nan'
a = pd.to_numeric(df.a, errors='coerce')
Utilisez isna pour renvoyer un index booléen:
idx = a.isna()
Appliquez cet index au bloc de données:
df[idx]
Renvoie la ligne contenant les mauvaises données:
a b
item
d bad 0.4
Si vous travaillez avec une colonne avec des valeurs de chaîne, vous pouvez utiliser la fonction très utile series.str.isnumeric () comme:
a = pd.Series(['hi','hola','2.31','288','312','1312', '0,21', '0.23'])
Ce que je fais est de copier cette colonne dans une nouvelle colonne et de faire un str.replace ('.', '') Et str.replace (',', ''), puis je sélectionne les valeurs numériques. et:
a = a.str.replace('.','')
a = a.str.replace(',','')
a.str.isnumeric()
Out [15]: 0 False 1 False 2 Vrai 3 Vrai 4 Vrai 5 Vrai 6 Vrai 7 Vrai dtype: bool
Bonne chance à tous!
Je pense à quelque chose comme, juste donner une idée, pour convertir la colonne en chaîne, et travailler avec une chaîne est plus facile. Cependant, cela ne fonctionne pas avec les chaînes contenant des nombres, comme bad123
. et ~
prend le complément de sélection.
df['a'] = df['a'].astype(str)
df[~df['a'].str.contains('0|1|2|3|4|5|6|7|8|9')]
df['a'] = df['a'].astype(object)
et en utilisant '|'.join([str(i) for i in range(10)])
pour générer '0|1|...|8|9'
ou en utilisant la fonction np.isreal()
, tout comme la réponse la plus votée
df[~df['a'].apply(lambda x: np.isreal(x))]