Удалить столбец из фрейма данных Pandas

1727

При удалении столбца в DataFrame я использую:

del df['column_name']

И это прекрасно работает. Почему я не могу использовать следующее?

del df.column_name

Поскольку можно получить доступ к столбцу / серии как df.column_name, я ожидал, что это сработает.

1
  • 2
    Обратите внимание, этот вопрос обсуждается на Meta .
    R.M.
    22 мая '19 в 16:37
2725

Лучший способ сделать это в Pandas - использовать drop:

df = df.drop('column_name', 1)

где 1- номер оси ( 0для строк и 1для столбцов).

Чтобы удалить столбец без переназначения, dfвы можете:

df.drop('column_name', axis=1, inplace=True)

Наконец, чтобы удалить по номеру столбца вместо метки столбца , попробуйте удалить это, например, 1-й, 2-й и 4-й столбцы:

df = df.drop(df.columns[[0, 1, 3]], axis=1)  # df.columns is zero-based pd.Index

Также работаем с «текстовым» синтаксисом для столбцов:

df.drop(['column_nameA', 'column_nameB'], axis=1, inplace=True)

Примечание. Метод drop (), представленный в версии 0.21.0 (27 октября 2017 г.), принимает ключевые слова index / columns в качестве альтернативы указанию оси.

Итак, теперь мы можем просто сделать:

df = df.drop(columns=['column_nameA', 'column_nameB'])
5
  • 95
    Это по delкакой-то причине рекомендуется ?
    beardc
    10 дек.
  • 27
    Хотя этот метод удаления имеет свои достоинства, этот ответ на самом деле не отвечает на задаваемый вопрос.
    Paul
    28 мая '14 в 12:59
  • 140
    Верно @Paul, но из-за названия вопроса большинство людей, прибывающих сюда, будут пытаться решить, как удалить столбец. 28 мая '14 в 16:43
  • 33
    @beardc еще одно преимущество dropover delзаключается в том, что dropвы можете удалить сразу несколько столбцов, выполнить операцию на месте или нет, а также удалить записи по любой оси (особенно полезно для трехмерной матрицы или Panel)
    hobs
    14 апр '16 в 20:17
  • 17
    Еще одно преимущество dropover delзаключается в том, что drop является частью API pandas и содержит документацию. 12 авг.
1201

Как вы уже догадались, правильный синтаксис

del df['column_name']

Трудно заставить del df.column_nameработать просто из-за синтаксических ограничений в Python. del df[name]переводится на df.__delitem__(name)Python под прикрытием.

8
  • 31 год
    Я понимаю, что это очень старый «ответ», но меня задето любопытство - почему это синтаксическое ограничение Python? class A(object): def __init__(self): self.var = 1настраивает класс, затем a = A(); del a.varработает нормально ... 4 окт.
  • 20
    @dwanderson разница в том, что когда столбец должен быть удален, DataFrame должен иметь собственную обработку для того, «как это сделать». В случае del df[name], он преобразуется в df.__delitem__(name)метод, который DataFrame может реализовать и изменить в соответствии со своими потребностями. В случае del df.name, переменная-член удаляется без возможности запуска какого-либо пользовательского кода. Рассмотрим свой собственный пример - можно ли получить del a.varвывод «удаление переменной»? Если можете, скажите, пожалуйста, как. Не могу :)
    Yonatan
    22 дек.
  • 8
    @Yonatan. Для этого можно использовать либо docs.python.org/3/reference/datamodel.html#object.__delattr__, либо дескрипторы: docs.python.org/3/howto/descriptor.html 19 янв.
  • 5
    Комментарий @Yonatan Eugene применим и к Python 2; дескрипторы присутствуют в Python 2 начиная с версии 2.2, и удовлетворить ваши требования несложно;)
    C S
    20 июн.
  • 3
    Этот ответ не совсем правильный - pandasразработчики этого не сделали , но это не значит, что это сложно сделать. 30 сен.
285

Использовать:

columns = ['Col1', 'Col2', ...]
df.drop(columns, inplace=True, axis=1)

Это приведет к удалению одного или нескольких столбцов на месте. Обратите внимание, что это inplace=Trueбыло добавлено в pandas v0.13 и не будет работать в более старых версиях. В этом случае вам нужно будет вернуть результат:

df = df.drop(columns, axis=1)
0
139

По индексу

Удалите первый, второй и четвертый столбцы:

df.drop(df.columns[[0,1,3]], axis=1, inplace=True)

Удалить первый столбец:

df.drop(df.columns[[0]], axis=1, inplace=True)

Существует необязательный параметр inplace, позволяющий изменять исходные данные без создания копии.

Выскочил

Выбор столбца, добавление, удаление

Удалить столбец column-name:

df.pop('column-name')

Примеры:

df = DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6]), ('C', [7,8, 9])], orient='index', columns=['one', 'two', 'three'])

print df:

   one  two  three
A    1    2      3
B    4    5      6
C    7    8      9

df.drop(df.columns[[0]], axis=1, inplace=True) print df:

   two  three
A    2      3
B    5      6
C    8      9

three = df.pop('three') print df:

   two
A    2
B    5
C    8
0
81

Фактический вопрос, на который не хватает большинства ответов, таков:

Почему я не могу использовать del df.column_name?

Сначала нам нужно понять проблему, которая требует от нас погрузиться в магические методы Python .

Как указывает Уэс в своем ответе, del df['column']отображается волшебный метод Python, df.__delitem__('column')который реализован в Pandas для удаления столбца .

Однако, как указано в приведенной выше ссылке о магических методах Python :

In fact, __del__ should almost never be used because of the precarious circumstances under which it is called; use it with caution!

Вы можете возразить, что это del df['column_name']не следует использовать или поощрять, и, следовательно, del df.column_nameне следует даже рассматривать.

Однако теоретически del df.column_nameможно реализовать работу в Pandas с помощью магического метода__delattr__ . Однако это создает определенные проблемы, проблемы, которые del df['column_name']уже есть в реализации, но в меньшей степени.

Пример проблемы

Что, если я определю столбец в фрейме данных с именем «dtypes» или «columns»?

Затем предположим, что я хочу удалить эти столбцы.

del df.dtypesможет __delattr__сбить метод с толку, как если бы он должен был удалить атрибут «dtypes» или столбец «dtypes».

Архитектурные вопросы, стоящие за этой проблемой

  1. Является ли фрейм данных набором столбцов ?
  2. Является ли фрейм данных набором строк ?
  3. Является ли столбец атрибутом фрейма данных?

Панды отвечают:

  1. Да во всех отношениях
  2. Нет, но если вы хотите быть, вы можете использовать .ix, .locили .ilocметоды.
  3. Может быть, вы хотите прочитать данные? Тогда да , если имя атрибута уже не занято другим атрибутом, принадлежащим фрейму данных. Вы хотите изменить данные? Тогда нет .

TL; DR;

Вы не можете этого сделать del df.column_name, потому что Pandas имеет довольно дико разросшуюся архитектуру, которую необходимо пересмотреть, чтобы такого рода когнитивный диссонанс не возник у ее пользователей.

Тип профи:

Не используйте df.column_name. Это может быть красиво, но вызывает когнитивный диссонанс .

Цитаты Zen of Python, которые подходят здесь:

Есть несколько способов удалить столбец.

There should be one-- and preferably only one --obvious way to do it.

Столбцы иногда являются атрибутами, а иногда - нет.

Special cases aren't special enough to break the rules.

Есть ли del df.dtypesудалить атрибут dtypes или столбец dtypes?

In the face of ambiguity, refuse the temptation to guess.

1
  • 1
    Фактически относится к части исходного вопроса ПОЧЕМУ. Я реализовал подклассы из фрейма данных pandas. Это научит вас важной части этого ответа. Различение атрибутов и имен столбцов - большая проблема. df.a оставляет неопределенность, является ли a атрибутом или именем столбца. Однако, как написано pandas, df ["a"] может быть только столбцом. 21 июл в 4:43
66

Приятным дополнением является возможность удалять столбцы, только если они существуют . Таким образом, вы можете охватить больше вариантов использования, и он удалит только существующие столбцы из переданных ему меток:

Просто добавьте, например, errors = 'ignore' :

df.drop(['col_name_1', 'col_name_2', ..., 'col_name_N'], inplace=True, axis=1, errors='ignore')
  • Это новинка от pandas 0.16.1 и выше. Документация здесь .
46

Начиная с версии 0.16.1, вы можете делать

df.drop(['column_name'], axis = 1, inplace = True, errors = 'ignore')
1
  • 3
    И это также поддерживает удаление нескольких столбцов, некоторые из которых могут не существовать (т. Е. Без возникновения ошибки errors= 'ignore') df.drop(['column_1','column_2'], axis=1 , inplace=True,errors= 'ignore'), если такое приложение желает!
    muon
    21 окт.
36

Хорошая практика - всегда использовать []обозначения. Одна из причин заключается в том, что нотация атрибута ( df.column_name) не работает для нумерованных индексов:

In [1]: df = DataFrame([[1, 2, 3], [4, 5, 6]])

In [2]: df[1]
Out[2]:
0    2
1    5
Name: 1

In [3]: df.1
  File "<ipython-input-3-e4803c0d1066>", line 1
    df.1
       ^
SyntaxError: invalid syntax
0
30

Панды 0.21+ ответ

Панды версия 0,21 изменила dropнемного способа включать как indexи columnsпараметры соответствуют Сигнатуре renameи reindexметодов.

df.drop(columns=['column_a', 'column_c'])

Лично я предпочитаю использовать axisпараметр для обозначения столбцов или индекса, потому что это основной параметр ключевого слова, используемый почти во всех методах pandas. Но теперь у вас есть несколько дополнительных возможностей в версии 0.21.

0
23

В Pandas 0.16.1+ вы можете удалять столбцы, только если они существуют в решении, опубликованном eiTan LaVi . До этой версии вы могли достичь того же результата с помощью понимания условного списка:

df.drop([col for col in ['col_name_1','col_name_2',...,'col_name_N'] if col in df],
        axis=1, inplace=True)
21

Использовать:

df.drop('columnname', axis =1, inplace = True)

Или вы можете пойти с

del df['colname']

Чтобы удалить несколько столбцов на основе номеров столбцов

df.drop(df.iloc[:,1:3], axis = 1, inplace = True)

Чтобы удалить несколько столбцов на основе имен столбцов

df.drop(['col1','col2',..'coln'], axis = 1, inplace = True)
0
18

TL; DR

Приложено много усилий, чтобы найти чуть более эффективное решение. Трудно оправдать добавленную сложность, жертвуя простотойdf.drop(dlst, 1, errors='ignore')

df.reindex_axis(np.setdiff1d(df.columns.values, dlst), 1)

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

Я также сосредоточусь на общем решении - удалить сразу несколько столбцов и разрешить попытку удаления столбцов, которых нет.

Эти решения являются общими и будут работать и в простом случае.


Настройка
Примите во внимание pd.DataFrame dfсписок и, которые необходимо удалитьdlst

df = pd.DataFrame(dict(zip('ABCDEFGHIJ', range(1, 11))), range(3))
dlst = list('HIJKLM')

df

   A  B  C  D  E  F  G  H  I   J
0  1  2  3  4  5  6  7  8  9  10
1  1  2  3  4  5  6  7  8  9  10
2  1  2  3  4  5  6  7  8  9  10

dlst

['H', 'I', 'J', 'K', 'L', 'M']

Результат должен выглядеть так:

df.drop(dlst, 1, errors='ignore')

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

Поскольку я приравниваю удаление столбца к выбору других столбцов, я разделю его на два типа:

  1. Выбор ярлыка
  2. Логический выбор

Выбор метки

Мы начинаем с создания списка / массива меток, которые представляют столбцы, которые мы хотим сохранить, и без столбцов, которые мы хотим удалить.

  1. df.columns.difference(dlst)

    Index(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype='object')
    
  2. np.setdiff1d(df.columns.values, dlst)

    array(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype=object)
    
  3. df.columns.drop(dlst, errors='ignore')

    Index(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype='object')
    
  4. list(set(df.columns.values.tolist()).difference(dlst))

    # does not preserve order
    ['E', 'D', 'B', 'F', 'G', 'A', 'C']
    
  5. [x for x in df.columns.values.tolist() if x not in dlst]

    ['A', 'B', 'C', 'D', 'E', 'F', 'G']
    

Столбцы из меток
Предположим, что для сравнения процесса выбора:

 cols = [x for x in df.columns.values.tolist() if x not in dlst]

Тогда мы можем оценить

  1. df.loc[:, cols]
  2. df[cols]
  3. df.reindex(columns=cols)
  4. df.reindex_axis(cols, 1)

Которые все оценивают так:

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

Логический фрагмент

Мы можем построить массив / список логических значений для нарезки

  1. ~df.columns.isin(dlst)
  2. ~np.in1d(df.columns.values, dlst)
  3. [x not in dlst for x in df.columns.values.tolist()]
  4. (df.columns.values[:, None] != dlst).all(1)

Столбцы из Boolean
для сравнения

bools = [x not in dlst for x in df.columns.values.tolist()]
  1. df.loc[: bools]

Которые все оценивают так:

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

Надежное время

Функции

setdiff1d = lambda df, dlst: np.setdiff1d(df.columns.values, dlst)
difference = lambda df, dlst: df.columns.difference(dlst)
columndrop = lambda df, dlst: df.columns.drop(dlst, errors='ignore')
setdifflst = lambda df, dlst: list(set(df.columns.values.tolist()).difference(dlst))
comprehension = lambda df, dlst: [x for x in df.columns.values.tolist() if x not in dlst]

loc = lambda df, cols: df.loc[:, cols]
slc = lambda df, cols: df[cols]
ridx = lambda df, cols: df.reindex(columns=cols)
ridxa = lambda df, cols: df.reindex_axis(cols, 1)

isin = lambda df, dlst: ~df.columns.isin(dlst)
in1d = lambda df, dlst: ~np.in1d(df.columns.values, dlst)
comp = lambda df, dlst: [x not in dlst for x in df.columns.values.tolist()]
brod = lambda df, dlst: (df.columns.values[:, None] != dlst).all(1)

Тестирование

res1 = pd.DataFrame(
    index=pd.MultiIndex.from_product([
        'loc slc ridx ridxa'.split(),
        'setdiff1d difference columndrop setdifflst comprehension'.split(),
    ], names=['Select', 'Label']),
    columns=[10, 30, 100, 300, 1000],
    dtype=float
)

res2 = pd.DataFrame(
    index=pd.MultiIndex.from_product([
        'loc'.split(),
        'isin in1d comp brod'.split(),
    ], names=['Select', 'Label']),
    columns=[10, 30, 100, 300, 1000],
    dtype=float
)

res = res1.append(res2).sort_index()

dres = pd.Series(index=res.columns, name='drop')

for j in res.columns:
    dlst = list(range(j))
    cols = list(range(j // 2, j + j // 2))
    d = pd.DataFrame(1, range(10), cols)
    dres.at[j] = timeit('d.drop(dlst, 1, errors="ignore")', 'from __main__ import d, dlst', number=100)
    for s, l in res.index:
        stmt = '{}(d, {}(d, dlst))'.format(s, l)
        setp = 'from __main__ import d, dlst, {}, {}'.format(s, l)
        res.at[(s, l), j] = timeit(stmt, setp, number=100)

rs = res / dres

rs

                          10        30        100       300        1000
Select Label                                                           
loc    brod           0.747373  0.861979  0.891144  1.284235   3.872157
       columndrop     1.193983  1.292843  1.396841  1.484429   1.335733
       comp           0.802036  0.732326  1.149397  3.473283  25.565922
       comprehension  1.463503  1.568395  1.866441  4.421639  26.552276
       difference     1.413010  1.460863  1.587594  1.568571   1.569735
       in1d           0.818502  0.844374  0.994093  1.042360   1.076255
       isin           1.008874  0.879706  1.021712  1.001119   0.964327
       setdiff1d      1.352828  1.274061  1.483380  1.459986   1.466575
       setdifflst     1.233332  1.444521  1.714199  1.797241   1.876425
ridx   columndrop     0.903013  0.832814  0.949234  0.976366   0.982888
       comprehension  0.777445  0.827151  1.108028  3.473164  25.528879
       difference     1.086859  1.081396  1.293132  1.173044   1.237613
       setdiff1d      0.946009  0.873169  0.900185  0.908194   1.036124
       setdifflst     0.732964  0.823218  0.819748  0.990315   1.050910
ridxa  columndrop     0.835254  0.774701  0.907105  0.908006   0.932754
       comprehension  0.697749  0.762556  1.215225  3.510226  25.041832
       difference     1.055099  1.010208  1.122005  1.119575   1.383065
       setdiff1d      0.760716  0.725386  0.849949  0.879425   0.946460
       setdifflst     0.710008  0.668108  0.778060  0.871766   0.939537
slc    columndrop     1.268191  1.521264  2.646687  1.919423   1.981091
       comprehension  0.856893  0.870365  1.290730  3.564219  26.208937
       difference     1.470095  1.747211  2.886581  2.254690   2.050536
       setdiff1d      1.098427  1.133476  1.466029  2.045965   3.123452
       setdifflst     0.833700  0.846652  1.013061  1.110352   1.287831

fig, axes = plt.subplots(2, 2, figsize=(8, 6), sharey=True)
for i, (n, g) in enumerate([(n, g.xs(n)) for n, g in rs.groupby('Select')]):
    ax = axes[i // 2, i % 2]
    g.plot.bar(ax=ax, title=n)
    ax.legend_.remove()
fig.tight_layout()

Это относительно времени, необходимого для запуска df.drop(dlst, 1, errors='ignore'). Похоже, что после всех этих усилий мы лишь незначительно улучшили производительность.

введите описание изображения здесь

Если по факту лучшие решения используйте reindexили reindex_axisна взлом list(set(df.columns.values.tolist()).difference(dlst)). Близкая секунда, но все же немного лучше, чем dropесть np.setdiff1d.

rs.idxmin().pipe(
    lambda x: pd.DataFrame(
        dict(idx=x.values, val=rs.lookup(x.values, x.index)),
        x.index
    )
)

                      idx       val
10     (ridx, setdifflst)  0.653431
30    (ridxa, setdifflst)  0.746143
100   (ridxa, setdifflst)  0.816207
300    (ridx, setdifflst)  0.780157
1000  (ridxa, setdifflst)  0.861622
13

Мы можем удалить или удалить указанный столбец или указанные столбцы с помощью метода drop () .

Предположим, что df - это фрейм данных.

Столбец, который нужно удалить = column0

Code:

df = df.drop(column0, axis=1)

Чтобы удалить несколько столбцов col1, col2,. . . , coln, мы должны вставить в список все столбцы, которые необходимо удалить. Затем удалите их методом drop ().

Code:

df = df.drop([col1, col2, . . . , coln], axis=1)
0
6

Если исходный фрейм данных dfне слишком велик, у вас нет ограничений памяти, и вам нужно сохранить только несколько столбцов, или, если вы заранее не знаете имена всех дополнительных столбцов, которые вам не нужны, вы можете а также создайте новый фрейм данных только с нужными столбцами:

new_df = df[['spam', 'sausage']]
3

Точечный синтаксис работает в JavaScript, но не в Python.

  • Python: del df['column_name']
  • JavaScript: del df['column_name'] или del df.column_name
0
3

Удаление столбца с помощью ilocфункции dataframeи slicing, когда у нас есть типичное имя столбца с нежелательными значениями:

df = df.iloc[:,1:] # Removing an unnamed index column

Вот 0строка по умолчанию и 1первый столбец, следовательно, :,1:это наш параметр для удаления первого столбца.

0
2

Другой способ удаления столбца в Pandas DataFrame

Если вы не ищете удаления на месте, вы можете создать новый DataFrame, указав столбцы, используя DataFrame(...)функцию как:

my_dict = { 'name' : ['a','b','c','d'], 'age' : [10,20,25,22], 'designation' : ['CEO', 'VP', 'MD', 'CEO']}

df = pd.DataFrame(my_dict)

Создайте новый DataFrame как

newdf = pd.DataFrame(df, columns=['name', 'age'])

Вы получаете такой же хороший результат, как и при использовании del / drop.

1
  • 1
    Это технически правильно, но кажется глупым перечислять каждый столбец, который нужно сохранить, а не только один (или несколько) столбцов, которые вы хотите удалить.
    cs95
    23 мая '19 в 17:24