Удаление нескольких столбцов на основе имен столбцов в Pandas

94

У меня есть некоторые данные, и когда я их импортирую, я получаю следующие ненужные столбцы. Я ищу простой способ удалить все эти

   'Unnamed: 24', 'Unnamed: 25', 'Unnamed: 26', 'Unnamed: 27',
   'Unnamed: 28', 'Unnamed: 29', 'Unnamed: 30', 'Unnamed: 31',
   'Unnamed: 32', 'Unnamed: 33', 'Unnamed: 34', 'Unnamed: 35',
   'Unnamed: 36', 'Unnamed: 37', 'Unnamed: 38', 'Unnamed: 39',
   'Unnamed: 40', 'Unnamed: 41', 'Unnamed: 42', 'Unnamed: 43',
   'Unnamed: 44', 'Unnamed: 45', 'Unnamed: 46', 'Unnamed: 47',
   'Unnamed: 48', 'Unnamed: 49', 'Unnamed: 50', 'Unnamed: 51',
   'Unnamed: 52', 'Unnamed: 53', 'Unnamed: 54', 'Unnamed: 55',
   'Unnamed: 56', 'Unnamed: 57', 'Unnamed: 58', 'Unnamed: 59',
   'Unnamed: 60'

Они индексируются 0-индексированием, поэтому я попробовал что-то вроде

    df.drop(df.columns[[22, 23, 24, 25, 
    26, 27, 28, 29, 30, 31, 32 ,55]], axis=1, inplace=True)

Но это не очень эффективно. Я попытался написать несколько циклов for, но это показалось мне плохим поведением Pandas. Поэтому я задаю вопрос здесь.

Я видел несколько похожих примеров ( отбросьте несколько столбцов панд ), но это не отвечает на мой вопрос.

Пидар Койл
источник
2
Что значит «эффективный»? Он работает слишком медленно? Если ваша проблема заключается в том, что вы не хотите получать индексы всех столбцов, которые хотите удалить, обратите внимание, что вы можете просто df.dropуказать список имен столбцов:df.drop(['Unnamed: 24', 'Unnamed: 25', ...], axis=1)
Carsten
Разве не было бы проще просто разделить интересующие столбцы на подмножества: то есть df = df[cols_of_interest], в противном случае вы могли бы разрезать df по столбцам и получить столбцыdf.drop(df.ix[:,'Unnamed: 24':'Unnamed: 60'].head(0).columns, axis=1)
EdChum
2
Я имел в виду неэффективность с точки зрения набора текста или «плохого запаха кода»,
Пидар Койл
1
Возможно, стоит отметить, что в большинстве случаев проще просто сохранить нужные столбцы, а затем удалить те, которые вам не нужны: df = df ['col_list']
sparrow

Ответы:

65

Я не знаю, что вы имеете в виду под неэффективным, но если вы имеете в виду с точки зрения набора текста, может быть проще просто выбрать интересующие столбцы и вернуть их в df:

df = df[cols_of_interest]

Где cols_of_interestнаходится список интересующих вас столбцов.

Или вы можете нарезать столбцы и передать это drop:

df.drop(df.ix[:,'Unnamed: 24':'Unnamed: 60'].head(0).columns, axis=1)

Вызов to headпросто выбирает 0 строк, поскольку нас интересуют только имена столбцов, а не данные

Обновить

Другой метод: было бы проще использовать булеву маску str.containsи инвертировать ее, чтобы замаскировать столбцы:

In [2]:
df = pd.DataFrame(columns=['a','Unnamed: 1', 'Unnamed: 1','foo'])
df

Out[2]:
Empty DataFrame
Columns: [a, Unnamed: 1, Unnamed: 1, foo]
Index: []

In [4]:
~df.columns.str.contains('Unnamed:')

Out[4]:
array([ True, False, False,  True], dtype=bool)

In [5]:
df[df.columns[~df.columns.str.contains('Unnamed:')]]

Out[5]:
Empty DataFrame
Columns: [a, foo]
Index: []
EdChum
источник
Я получаю ошибки, когда пытаюсь выполнить либо ~ df.columns ... (TypeError: неверный тип операнда для унарного ~: 'str'), либо df.columns.str.contains ... (AttributeError: объект 'Index' не имеет атрибута 'ул'). Есть идеи, почему это может быть?
Дай
@EdChum, могу ли я создать df = df [cols_of_interest] , где cols_of_interest добавляет имя столбца к нему каждый раз, когда цикл for повторяется?
@Victor нет, если вы это сделаете, вы перезапишете свой dfновый столбец, appendвозможно, вам стоит, но я действительно не понимаю ваш вопрос, вы должны опубликовать реальный вопрос на SO, а не спрашивать как комментарий, поскольку это плохая форма на SO
EdChum
@EdChum, ты абсолютно прав. Я создал вопрос и пытаюсь решить его, выполнив поиск в разных частях SO. Вот ссылка ! любой вклад поможет stackoverflow.com/questions/48923915/…
213

Самый простой подход:

yourdf.drop(['columnheading1', 'columnheading2'], axis=1, inplace=True)
Филипп Шварц
источник
1
Я использовал этот формат в каком-то коде и получаю SettingWithCopyWarningпредупреждение?
KillerSnail
2
@KillerSnail, это можно игнорировать. Чтобы избежать ошибки, попробуйте: df = df.drop (['colheading1', 'colheading2'], axis = 1)
Филипп Шварц
5
axisОбъяснение термина : stackoverflow.com/questions/22149584/… . По сути, axis=0считается «по столбцам» и axis=1«по строкам».
Rohmer
5
И inplace=Trueозначает, что DataFrameмодифицируется на месте.
Rohmer
1
@Killernail, если вам не нужно предупреждение, сделайтеyourdf = yourdf.drop(['columnheading1', 'columnheading2'], axis=1)
happy_sisyphus
41

Мой личный фаворит, и он проще, чем ответы, которые я видел здесь (для нескольких столбцов):

df.drop(df.columns[22:56], axis=1, inplace=True)

Или создать список из нескольких столбцов.

col = list(df.columns)[22:56]
df.drop(col, axis=1, inplace=1)
Шелдонзи
источник
8
Это должен быть ответ. Самый чистый, легкий для чтения, с простым синтаксисом индексации Pandas.
Brent Faust
2
Рядом с этим ответом должна быть зеленая галочка, а не другие.
Сиавош Махбубиан
1
Небольшая поправка (если не ошибаюсь): во втором блоке кода должно быть inplace = True вместо inplace = 1.
Тредолсен,
20

Вероятно, это хороший способ делать то, что вы хотите. Он удалит все столбцы, содержащие «Безымянный» в заголовке.

for col in df.columns:
    if 'Unnamed' in col:
        del df[col]
рыцарь
источник
это for col in df.columns:можно упростить for col in df:, также OP не указал, какова схема именования для других столбцов, все они могут содержать
``
Это, конечно, неэффективно, но пока мы не работаем с огромными фреймами данных, это не окажет значительного влияния. Плюс этого метода в том, что его легко запомнить и быстро кодировать - создание списка столбцов, которые вы хотите сохранить, может быть довольно болезненным.
Knightofni
Я думаю, что это, вероятно, будет наиболее эффективным на больших df, потому что вам не нужно делать локальную копию сinplace = True
Мэтт
13

Вы можете сделать это одной строкой и за один раз:

df.drop([col for col in df.columns if "Unnamed" in col], axis=1, inplace=True)

Это требует меньшего перемещения / копирования объекта, чем описанные выше решения.

Питер
источник
11

Не уверен, упоминалось ли это решение где-либо, но есть один способ сделать это pandas.Index.difference.

>>> df = pd.DataFrame(columns=['A','B','C','D'])
>>> df
Empty DataFrame
Columns: [A, B, C, D]
Index: []
>>> to_remove = ['A','C']
>>> df = df[df.columns.difference(to_remove)]
>>> df
Empty DataFrame
Columns: [B, D]
Index: []
px06
источник
4

Вы можете просто передать имена столбцов в виде списка с указанием оси как 0 или 1

  • axis = 1: Вдоль строк
  • axis = 0: Вдоль столбцов
  • По умолчанию ось = 0

    data.drop(["Colname1","Colname2","Colname3","Colname4"],axis=1)

Мадду Сваруп
источник
4

Просто и легко. Удалите все столбцы после 22 числа.

df.drop(columns=df.columns[22:]) # love it
Niedson
источник
Чтобы изменить dfна месте, добавьте флаг inplace=True, так чтоdf.drop(columns=df.columns[22:], inplace=True)
arilwan
1

Ниже сработало для меня:

for col in df:
    if 'Unnamed' in col:
        #del df[col]
        print col
        try:
            df.drop(col, axis=1, inplace=True)
        except Exception:
            pass
Шивган
источник
0

df = df[[col for col in df.columns if not ('Unnamed' in col)]]

Сара
источник
1
Это похоже на метод Питера, за исключением того, что нежелательные столбцы отфильтровываются, а не удаляются.
Сара