python - примеры - pandas series to dataframe




Удалить столбец из pandas DataFrame с помощью del df.column_name (10)

Pandas 0.21+ ответ

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

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

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

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

del df['column_name']

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

del df.column_name

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


TL; DR

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

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

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

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

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

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

Если факт, что лучшие решения используют reindex или reindex_axis в list(set(df.columns.values.tolist()).difference(dlst)) взлома list(set(df.columns.values.tolist()).difference(dlst)) . np.setdiff1d секунда и все еще очень незначительно лучше, чем 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

В 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)

Если вы хотите сбросить один столбец ( 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 ), попробуйте col_lst = [col_name_1,col_name_2,...] одно из следующих действий:

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

ИЛИ ЖЕ

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

TLDR;

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

Protip:

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

Zen of Python цитирует, что подходит здесь:

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

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

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

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

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

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


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

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

Еще один способ удаления столбца в Pandas DataFrame

если вы не ищете удаление In-Place, вы можете создать новый 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







dataframe