it-roy-ru.com

Удалить столбец из pandas DataFrame

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

del df['column_name']

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

del df.column_name

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

1003
John

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

512
Wes McKinney

Лучший способ сделать это в пандах - это использовать 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 
1681
LondonRob

Использование:

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

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

df = df.drop(columns, axis=1)
194
Krishna Sankar

Падение по индексу

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

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
90
jezrael

Фактический вопрос, который пропущен большинством ответов здесь:

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

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

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

Тем не менее, как указано в ссылке выше о python magic tools :

Фактически, del почти никогда не должен использоваться из-за сомнительных обстоятельств, при которых он вызывается; используйте это с осторожностью!

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

Тем не менее, теоретически, del df.column_name может быть реализован для работы в пандах с использованием метода magic __delattr__ . Это, однако, создает определенные проблемы, проблемы, которые уже есть у реализации del df['column_name'], но в меньшей степени.

Пример задачи

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

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

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

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

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

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

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

TLDR;

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

Protip:

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

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

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

Должен быть один - и желательно только один - очевидный способ сделать это.

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

Особые случаи не достаточно особенные, чтобы нарушать правила.

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

Перед лицом двусмысленности откажитесь от соблазна гадать.

57
firelynx

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

Просто добавьте ошибки = 'игнорировать' , например:

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

с версии 0.16.1 вы можете сделать 

df.drop(['column_name'], axis = 1, inplace = True, errors = 'ignore')
39
sushmit

Рекомендуется всегда использовать нотацию []. Одна из причин заключается в том, что нотация атрибута (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
26
Andy Hayden

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

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

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

Версия P.21 0.21 немного изменила метод drop , добавив в него параметры index и columns, чтобы соответствовать сигнатуре методов rename и reindex

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

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

15
Ted Petrou

TL; DR

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

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

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

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

Использование этих решений носит общий характер и будет работать и для простого случая.


Настройка
Рассмотрим pd.DataFramedf и список для удаления 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)

Столбцы из логического типа
Для сравнения 

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'). Кажется, что после всех этих усилий мы лишь незначительно улучшаем производительность.

 enter image description here

Если факт, то лучшие решения используют 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
11
piRSquared

Если вы хотите удалить один столбец (col_name) из кадра данных (df), попробуйте выполнить одно из следующих действий:

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

ИЛИ ЖЕ 

df.drop(col_name, axis=1, inplace=True)

Если вы хотите удалить список столбцов (col_lst = [col_name_1,col_name_2,...]) из фрейма данных (df), попробуйте выполнить одно из следующих действий:

df.drop(col_lst, axis=1, inplace=True)

ИЛИ ЖЕ 

df.drop(columns=col_lst, inplace=True)
7
Stephanie

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

  • Python: del df['column_name']
  • JavaScript: del df['column_name'] или del df.column_name
2
Doctor

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

Если вы пришли сюда в поисках информации о том, как удалить столбец (с тем же именем) из списка DataFrames, то есть несколько способов сделать это.

Одним из методов является перебор списка и изменение каждого DataFrame на месте:

# In-place assignment
for df in df_list:
    df.drop('colname', axis=1, inplace=True)

Или же,

for df in df_list: df.pop('colname')

Либо удалите столбец (не на месте) и присвойте результат обратно этой позиции в списке.

# Reassigning a copy back to the list
for i, df in enumerate(df_list):
    df_list[i] = df.drop('colname', axis=1, inplace=True)

Воспроизводимый пример кода

df1 = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
df2 = pd.DataFrame({'A': [4, 5, 7], 'C': ['a', 'b', 'c']})

df1
   A  B
0  1  4
1  2  5
2  3  6

df2
   A  C
0  4  a
1  5  b
2  7  c

df_list = [df1, df2]
# Drop column "A"
for df in df_list:
    df.drop('A', axis=1, inplace=True)

df1
   B
0  4
1  5
2  6

df2
   C
0  a
1  b
2  c

Почему for df in df_list: df = df.drop('colname', axis=1) (т.е. переназначение внутри цикла) не работает?

Как упоминалось в других ответах, df.drop возвращает копию по умолчанию. Копия возвращается и повторно присваивается переменнаяdf, без каких-либо изменений в оригинале. Вам нужно будет либо изменить df на месте с аргументом inplace=True, либо явно переназначить копию этому элементу списка.

Заметка
Важно понимать разницу между переменными и объектами. Переменные содержат ссылки на объекты. Переменные могут быть переназначены для ссылки на разные объекты, это не имеет ничего общего с изменением самого объекта. Для хорошего изучения этой темы я рекомендую прочитать эту статью Неда Батчелдера.

1
cs95

попробуйте это, я думаю, что это самый простой способ:

drop((['A','B'],axis=1)

0
Aymen Alsaadi

Еще один способ удаления столбца в 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

0
Daksh