Поиск нечисловых строк в 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')]

Просто отфильтровывать строки не содержит никакого числа?