Поиск нечисловых строк в dataframe в pandas?
У меня есть большой фреймворк данных в pandas, который, кроме столбца, используемого как индекс, должен иметь только числовые значения:
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')
Как я могу найти строку фрейма данных df
, в которой есть нечисловое значение?
В этом примере это четвертая строка в фрейме данных, которая имеет строку 'bad'
в столбце a
. Как эта строка может быть найдена программно?
Ответы
Ответ 1
Вы можете использовать np.isreal
, чтобы проверить тип каждого элемента (applymap применяет функцию к каждому элементу в 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
Если все в строке имеют значение Истина, все они являются числовыми:
In [12]: df.applymap(np.isreal).all(1)
Out[12]:
item
a True
b True
c True
d False
e True
dtype: bool
Итак, чтобы получить subDataFrame из rouges, (Примечание: отрицание, ~, из вышеперечисленного находит те, у которых есть хотя бы один изгоев нечисловой):
In [13]: df[~df.applymap(np.isreal).all(1)]
Out[13]:
a b
item
d bad 0.4
Вы также можете найти местоположение первого правонарушителя, которого вы могли бы использовать argmin:
In [14]: np.argmin(df.applymap(np.isreal).all(1))
Out[14]: 'd'
Как указывает @CTZhu, он может быть немного быстрее проверить, является ли это экземпляром либо int, либо float (есть некоторые дополнительные накладные расходы с np.isreal):
df.applymap(lambda x: isinstance(x, (int, float)))
Ответ 2
Уже некоторые замечательные ответы на этот вопрос, однако вот хороший фрагмент, который я использую регулярно, чтобы отбрасывать строки, если у них есть нечисловые значения в некоторых столбцах:
# Eliminate invalid data from dataframe (see Example below for more context)
numdf = (df.drop(data_columns, axis=1)
.join(df[data_columns].apply(pd.to_numeric, errors='coerce')))
numdf = numdf[num_df[data_columns].notnull().all(axis=1)]
Как это работает, мы сначала drop
все data_columns
из df
, а затем используйте join
, чтобы вернуть их после прохождения через pd.to_numeric
(с опцией 'coerce'
, так что все нечисловые записи преобразуются в NaN
). Результат сохраняется до numdf
.
Во второй строке мы используем фильтр, который хранит только строки, где все значения не равны нулю.
Обратите внимание, что pd.to_numeric
принуждает NaN
все, что невозможно преобразовать в числовое значение, поэтому строки, которые представляют числовые значения, не будут удалены. Например, '1.25'
будет распознаваться как числовое значение 1.25
.
Отказ от ответственности: pd.to_numeric
был представлен в версии pandas 0.17.0
Пример:
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
Ответ 3
Извините за путаницу, это должен быть правильный подход. Вы хотите только захватить только 'bad'
, а не такие вещи, как 'good'
; Или просто любые не численные значения?
In[15]:
np.where(np.any(np.isnan(df.convert_objects(convert_numeric=True)), axis=1))
Out[15]:
(array([3]),)
Ответ 4
# 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')
Преобразовать в числовое значение с помощью 'coerce', который заполняет неверные значения с помощью 'nan'
a = pd.to_numeric(df.a, errors='coerce')
Используйте isna для возврата логического индекса:
idx = a.isna()
Примените этот индекс к фрейму данных:
df[idx]
выход
Возвращает строку с неверными данными в ней:
a b
item
d bad 0.4
Ответ 5
Если вы работаете со столбцом со строковыми значениями, вы можете использовать
ОЧЕНЬ ПОЛЕЗНАЯ функция series.str.isnumeric() как:
a = pd.Series(['hi','hola','2.31','288','312','1312', '0,21', '0.23'])
Что я делаю, это скопировать этот столбец в новый столбец и сделать str.replace('.', '') и str.replace(',', ''), после чего я выберу числовые значения.
и:
a = a.str.replace('.','')
a = a.str.replace(',','')
a.str.isnumeric()
Из [15]:
0 Неверно
1 Неверно
2 Правда
3 Истинный
4 Истинный
5 Правда
6 Правда
7 Правда
dtype: bool
Удачи всем!
Ответ 6
Я думаю что-то вроде
df[~df[''].str.contains('0|1|2|3|4|5|6|7|8|9')]
Просто отфильтровывать строки не содержит никакого числа?