Excluindo várias colunas com base nos nomes das colunas no Pandas

96

Eu tenho alguns dados e quando os importo obtenho as seguintes colunas desnecessárias, estou procurando uma maneira fácil de excluir todas elas

   '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'

Eles são indexados por indexação 0, então tentei algo como

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

Mas isso não é muito eficiente. Tentei escrever alguns loops for, mas isso me pareceu um comportamento ruim do Pandas. Portanto, faço a pergunta aqui.

Eu vi alguns exemplos que são semelhantes ( pandas de várias colunas ), mas isso não responde à minha pergunta.

Peadar Coyle
fonte
2
O que você quer dizer com eficiente? Está muito lento? Se o seu problema é que você não deseja obter os índices de todas as colunas que deseja excluir, observe que você pode apenas fornecer df.dropuma lista dos nomes das colunas:df.drop(['Unnamed: 24', 'Unnamed: 25', ...], axis=1)
Carsten
Não seria mais fácil apenas subdividir as colunas de interesse: ou seja df = df[cols_of_interest], caso contrário, você poderia df.drop(df.ix[:,'Unnamed: 24':'Unnamed: 60'].head(0).columns, axis=1)
dividir
2
Eu quis dizer ineficiente em termos de digitação ou 'cheiro de código ruim'
Peadar Coyle
1
Pode ser interessante notar que na maioria dos casos é mais fácil apenas manter as colunas que você deseja, em seguida, excluir as que você não deseja: df = df ['col_list']
sparrow

Respostas:

65

Eu não sei o que você quer dizer com ineficiente, mas se você quer dizer em termos de digitação, poderia ser mais fácil apenas selecionar as colunas de interesse e atribuir de volta ao df:

df = df[cols_of_interest]

Onde cols_of_interestestá uma lista das colunas de seu interesse.

Ou você pode fatiar as colunas e passar isso para drop:

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

A chamada para headseleciona apenas 0 linhas, pois estamos interessados ​​apenas nos nomes das colunas, e não nos dados

atualizar

Outro método: seria mais simples usar a máscara booleana str.containse invertê-la para mascarar as colunas:

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
fonte
Recebo erros quando tento fazer ~ df.columns ... (TypeError: tipo de operando incorreto para unário ~: 'str') ou df.columns.str.contains ... (AttributeError: objeto 'Index' não tem atributo 'str'). Alguma ideia de por que isso pode ser?
Dai
@EdChum posso criar df = df [cols_of_interest] , onde cols_of_interest adiciona um nome de coluna a ele toda vez que um loop for itera?
@Victor não, se você fizer isso, substitua sua dfnova coluna, appendtalvez deva, mas eu realmente não entendo sua pergunta, você deve postar uma pergunta real no SO em vez de perguntar como um comentário, pois é de má qualidade no SO
EdChum
@EdChum você está absolutamente certo. Eu criei a questão e estou tentando resolvê-la pesquisando diferentes partes do SO. Aqui está o link ! qualquer contribuição ajudará stackoverflow.com/questions/48923915/…
220

De longe, a abordagem mais simples é:

yourdf.drop(['columnheading1', 'columnheading2'], axis=1, inplace=True)
Philipp Schwarz
fonte
1
Usei esse formato em algum do meu código e recebo um SettingWithCopyWarningaviso?
KillerSnail
2
@KillerSnail, é salvo para ignorar. Para evitar erros, tente: df = df.drop (['colheading1', 'colheading2'], axis = 1)
Philipp Schwarz
6
O termo axisexplicado: stackoverflow.com/questions/22149584/… . Essencialmente, axis=0é dito "em termos de coluna" e axis=1"em termos de linha".
Rohmer
6
E inplace=Truesignifica que o DataFrameé modificado no lugar.
Rohmer
1
@Killernail se você não quiser o aviso, façayourdf = yourdf.drop(['columnheading1', 'columnheading2'], axis=1)
happy_sisyphus
41

Meu favorito pessoal e mais fácil do que as respostas que vi aqui (para várias colunas):

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

Ou criando uma lista para várias colunas.

col = list(df.columns)[22:56]
df.drop(col, axis=1, inplace=1)
Sheldonzy
fonte
8
Esta deve ser a resposta. Mais limpo e fácil de ler, com sintaxe de indexação nativa simples do Pandas.
Brent Faust
2
Essa resposta deve ter uma marca verde próxima a ela, não as outras.
Siavosh Mahboubian de
1
Pequena correção (a menos que eu esteja enganado): o segundo bloco de código deve ter 'inplace = True' em vez de 'inplace = 1'.
Thredolsen,
20

Esta é provavelmente uma boa maneira de fazer o que você deseja. Isso excluirá todas as colunas que contêm 'Sem nome' no cabeçalho.

for col in df.columns:
    if 'Unnamed' in col:
        del df[col]
Knightofni
fonte
isso for col in df.columns:pode ser simplificado para for col in df:, também o OP não indicou qual é o esquema de nomenclatura para as outras colunas, todas elas poderiam conter 'Sem nome', também é ineficiente, pois remove as colunas uma de cada vez
EdChum
Certamente não é eficiente, mas enquanto não trabalharmos em grandes dataframes, não terá um impacto significativo. O ponto positivo desse método é que ele é simples de lembrar e rápido de codificar - enquanto a criação de uma lista das colunas que você deseja manter pode ser muito trabalhosa.
knightofni
Acho que é provável que tenha mais desempenho em grande df porque você não precisa fazer uma cópia local cominplace = True
Matt
13

Você pode fazer isso em uma linha e de uma vez:

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

Isso envolve menos movimentação / cópia do objeto do que as soluções acima.

Peter
fonte
11

Não tenho certeza se esta solução foi mencionada em algum lugar ainda, mas uma maneira de fazer é 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
fonte
4

Você pode simplesmente passar os nomes das colunas como uma lista especificando o eixo como 0 ou 1

  • eixo = 1: ao longo das linhas
  • eixo = 0: ao longo das colunas
  • Por eixo padrão = 0

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

Maddu Swaroop
fonte
4

Simples e fácil. Remova todas as colunas após o dia 22.

df.drop(columns=df.columns[22:]) # love it
Niedson
fonte
Para modificar dfno local, adicione o sinalizador inplace=True, Entãodf.drop(columns=df.columns[22:], inplace=True)
arilwan
1

O seguinte funcionou para mim:

for col in df:
    if 'Unnamed' in col:
        #del df[col]
        print col
        try:
            df.drop(col, axis=1, inplace=True)
        except Exception:
            pass
Shivgan
fonte
0

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

Sarah
fonte
1
Isso é semelhante ao de Peter, exceto que as colunas indesejadas são filtradas em vez de eliminadas.
Sarah