Selecionando várias colunas em um dataframe do pandas


1113

Eu tenho dados em colunas diferentes, mas não sei como extraí-los para salvá-los em outra variável.

index  a   b   c
1      2   3   4
2      3   4   5

Como faço para selecionar 'a', 'b'e guardá-lo para DF1?

eu tentei

df1 = df['a':'b']
df1 = df.ix[:, 'a':'b']

Nenhum parece funcionar.


2
Você nunca deseja usar .ix, pois é ambíguo. Use .ilocou .locse precisar.
Acumenus

1
Existe uma maneira de fazer isso sem consultar os nomes dos cabeçalhos? como em R, posso fazer assim: > csvtable_imp_1 <- csvtable_imp[0:6]e seleciona a quantidade delta das primeiras colunas entre 0 e 6. Tudo o que eu precisava fazer era ler a tabela csv conforme delimitada pela readr lib.
quer

Eu trabalhei um pouco mais com isso. Encontrei algo que funcionava como queria. O padrão é selecionar números de caracteres e não colunas. infile_1 = largefile_stay.ix[:,0:6]
quer

3
Para aqueles que tropeçam nesse atraso, ixagora está obsoleto. O Pandas recomenda o uso de: loc(indexação baseada em rótulo) ou iloc(indexação baseada em posição).
ZaydH

Respostas:


1770

Os nomes das colunas (que são cadeias) não podem ser divididos da maneira que você tentou.

Aqui você tem algumas opções. Se você souber do contexto quais variáveis ​​deseja separar, basta retornar uma exibição apenas dessas colunas, passando uma lista para a __getitem__sintaxe (os [] ').

df1 = df[['a','b']]

Como alternativa, se for importante indexá-los numericamente e não pelo nome (digamos que seu código faça isso automaticamente sem conhecer os nomes das duas primeiras colunas), você poderá fazer isso:

df1 = df.iloc[:,0:2] # Remember that Python does not slice inclusive of the ending index.

Além disso, você deve se familiarizar com a idéia de uma exibição em um objeto Pandas versus uma cópia desse objeto. O primeiro dos métodos acima retornará uma nova cópia na memória do subobjeto desejado (as fatias desejadas).

Às vezes, no entanto, existem convenções de indexação no Pandas que não fazem isso e fornecem uma nova variável que se refere apenas ao mesmo pedaço de memória que o subobjeto ou fatia no objeto original. Isso acontecerá com a segunda maneira de indexação, para que você possa modificá-lo com a copy()função para obter uma cópia regular. Quando isso acontece, alterar o que você acha que é o objeto fatiado pode às vezes alterar o objeto original. É sempre bom estar atento a isso.

df1 = df.iloc[0,0:2].copy() # To avoid the case where changing df1 also changes df

Para usar iloc, você precisa conhecer as posições da coluna (ou índices). Como as posições da coluna podem mudar, em vez de índices codificados, você pode usar ilocjunto com a get_locfunção do columnsmétodo do objeto dataframe para obter índices da coluna.

{df.columns.get_loc(c):c for idx, c in enumerate(df.columns)}

Agora você pode usar este dicionário para acessar colunas através de nomes e usando iloc.


192
Nota: df[['a','b']]produz uma cópia
Wes McKinney

1
Sim, isso estava implícito na minha resposta. A parte sobre a cópia era apenas para uso ix[]se você preferir usar ix[]por qualquer motivo.
Ely

1
ixindexa linhas, não colunas. Eu pensei que o OP queria colunas.
hobs

9
ixaceita argumentos de fatia, para que você também possa obter colunas. Por exemplo, df.ix[0:2, 0:2]obtém o sub-array 2x2 superior esquerdo da mesma forma que para uma matriz NumPy (dependendo dos nomes das colunas, é claro). Você pode até usar a sintaxe da fatia nos nomes de string das colunas, como df.ix[0, 'Col1':'Col5']. Isso obtém todas as colunas que são ordenadas entre Col1e Col5na df.columnsmatriz. É incorreto dizer que ixindexa linhas. Esse é apenas o seu uso mais básico. Ele também suporta muito mais indexação do que isso. Então, ixé perfeitamente geral para esta pergunta.
Ely

7
@AndrewCassidy Nunca use .ix novamente. Se você deseja fatiar com números inteiros, use .ilocexclusivo da última posição, assim como as listas Python.
Ted Petrou

133

Na versão 0.11.0, as colunas podem ser divididas da maneira que você tentou usar o .locindexador:

df.loc[:, 'C':'E']

é equivalente a

df[['C', 'D', 'E']]  # or df.loc[:, ['C', 'D', 'E']]

e colunas de volta Catravés E.


Uma demonstração em um DataFrame gerado aleatoriamente:

import pandas as pd
import numpy as np
np.random.seed(5)
df = pd.DataFrame(np.random.randint(100, size=(100, 6)), 
                  columns=list('ABCDEF'), 
                  index=['R{}'.format(i) for i in range(100)])
df.head()

Out: 
     A   B   C   D   E   F
R0  99  78  61  16  73   8
R1  62  27  30  80   7  76
R2  15  53  80  27  44  77
R3  75  65  47  30  84  86
R4  18   9  41  62   1  82

Para obter as colunas de C a E (observe que, diferentemente da fatia inteira, 'E' está incluído nas colunas):

df.loc[:, 'C':'E']

Out: 
      C   D   E
R0   61  16  73
R1   30  80   7
R2   80  27  44
R3   47  30  84
R4   41  62   1
R5    5  58   0
...

O mesmo funciona para selecionar linhas com base em rótulos. Obtenha as linhas 'R6' para 'R10' dessas colunas:

df.loc['R6':'R10', 'C':'E']

Out: 
      C   D   E
R6   51  27  31
R7   83  19  18
R8   11  67  65
R9   78  27  29
R10   7  16  94

.loctambém aceita uma matriz booleana para que você possa selecionar as colunas cuja entrada correspondente na matriz é True. Por exemplo, df.columns.isin(list('BCD'))retorna array([False, True, True, True, False, False], dtype=bool)- True se o nome da coluna estiver na lista ['B', 'C', 'D']; Falso, caso contrário.

df.loc[:, df.columns.isin(list('BCD'))]

Out: 
      B   C   D
R0   78  61  16
R1   27  30  80
R2   53  80  27
R3   65  47  30
R4    9  41  62
R5   78   5  58
...

110

Supondo que os nomes das colunas ( df.columns) sejam ['index','a','b','c'], os dados que você deseja estão nas 3ª e 4ª colunas. Se você não souber o nome deles quando o script for executado, poderá fazer isso

newdf = df[df.columns[2:4]] # Remember, Python is 0-offset! The "3rd" entry is at slot 2.

Como o EMS aponta em sua resposta , df.ixcorta as colunas de maneira um pouco mais concisa, mas a .columnsinterface de fatiamento pode ser mais natural porque usa a sintaxe de indexação / faturamento de lista python 1-D de baunilha.

AVISO: 'index'é um nome ruim para uma DataFramecoluna. Esse mesmo rótulo também é usado para o df.indexatributo real , uma Indexmatriz. Portanto, sua coluna é retornada por df['index']e o índice DataFrame real é retornado por df.index. An Indexé um tipo especial de Seriesotimizado para a pesquisa dos valores de seus elementos. Para df.index, é procurar linhas pelo rótulo. Esse df.columnsatributo também é uma pd.Indexmatriz, para procurar colunas por seus rótulos.


3
Como observei no meu comentário acima, não.ix é apenas para linhas. É para fatias de uso geral e pode ser usado para fatias multidimensionais. É basicamente apenas uma interface para a sintaxe usual do NumPy . Dito isto, você pode facilmente converter um problema de divisão de colunas em um problema de divisão de linhas apenas aplicando uma operação de transposição . Seu exemplo usa , o que é um pouco enganador. O resultado de é a ; tenha cuidado para não tratá-lo apenas como uma matriz. Além disso, você provavelmente deve alterá-lo para corresponder ao seu comentário "3º e 4º". __getitem__df.Tcolumns[1:3]columnsSeriescolumns[2:3]
Ely

@ Mr.F: Meu [2:4]está correto. Você [2:3]está errado. E usar a notação padrão de fatia de python para gerar uma sequência / série não é um IMO enganoso. Mas eu gosto do seu desvio da interface do DataFrame para acessar a matriz numpy subjacente ix.
Placas,

Você está correto neste caso, mas o ponto que eu estava tentando enfatizar é que, em geral, fatiar com rótulos no Pandas inclui o ponto final da fatia (ou pelo menos esse era o comportamento na maioria das versões anteriores do Pandas). Portanto, se você o recuperar df.columnse desejar dividi-lo por rótulo , terá uma semântica de fatia diferente do que se você o dividisse pela posição do índice inteiro . Definitivamente, não o expliquei bem no meu comentário anterior.
ely

Ahh, agora entendo o seu ponto. Esqueci que columnsé uma série imutável e o getter foi substituído para usar rótulos como índices. Obrigado por reservar um tempo para esclarecer.
hobs

2
Observe que o aviso de reprovação: .ix está obsoleto. Portanto, isso faz sentido: newdf = df [df.columns [2: 4]]
Martien Lubberink

64
In [39]: df
Out[39]: 
   index  a  b  c
0      1  2  3  4
1      2  3  4  5

In [40]: df1 = df[['b', 'c']]

In [41]: df1
Out[41]: 
   b  c
0  3  4
1  4  5

1
E se eu quisesse renomear a coluna, por exemplo algo como: df[['b as foo', 'c as bar']tal que a saída renomeie a coluna bcomo fooe a coluna ccomo bar?
kuanb

5
df[['b', 'c']].rename(columns = {'b' : 'foo', 'c' : 'bar'})
25817 Greg Greg

62

Sei que essa pergunta é bastante antiga, mas na versão mais recente do pandas existe uma maneira fácil de fazer exatamente isso. Os nomes das colunas (que são cadeias) podem ser divididos da maneira que você desejar.

columns = ['b', 'c']
df1 = pd.DataFrame(df, columns=columns)

6
Isso só pode ser feito na criação. A questão é perguntar se você já o possui em um quadro de dados.
Banjocat

3
@Banjocat, ele trabalha com uma trama de dados existente
mhery

23

Você pode fornecer uma lista de colunas a serem descartadas e retornar o DataFrame apenas com as colunas necessárias, usando a drop()função em um DataFrame do Pandas.

Apenas dizendo

colsToDrop = ['a']
df.drop(colsToDrop, axis=1)

retornaria um DataFrame com apenas as colunas be c.

O dropmétodo está documentado aqui .


23

Com pandas,

com nomes de colunas

dataframe[['column1','column2']]

para selecionar por iloc e colunas específicas com número de índice:

dataframe.iloc[:,[1,2]]

com nomes de colunas loc pode ser usado como

dataframe.loc[:,['column1','column2']]

20

Eu achei esse método muito útil:

# iloc[row slicing, column slicing]
surveys_df.iloc [0:3, 1:4]

Mais detalhes podem ser encontrados aqui


Como você usaria, digamos, apenas as colunas 2 e 5?
324

1
Isso seria surveys_df.iloc [:, [2,5]]então.
Julian Gorfer

15

A partir de 0.21.0, o uso .locou []uma lista com um ou mais rótulos ausentes é preterido em favor de .reindex. Portanto, a resposta para sua pergunta é:

df1 = df.reindex(columns=['b','c'])

Nas versões anteriores, o uso .loc[list-of-labels]funcionaria contanto que pelo menos 1 das chaves fosse encontrada (caso contrário, aumentaria a KeyError). Esse comportamento foi descontinuado e agora mostra uma mensagem de aviso. A alternativa recomendada é usar .reindex().

Leia mais em Indexação e seleção de dados


10

Você pode usar pandas. Eu crio o DataFrame:

    import pandas as pd
    df = pd.DataFrame([[1, 2,5], [5,4, 5], [7,7, 8], [7,6,9]], 
                      index=['Jane', 'Peter','Alex','Ann'],
                      columns=['Test_1', 'Test_2', 'Test_3'])

O DataFrame:

           Test_1  Test_2  Test_3
    Jane        1       2       5
    Peter       5       4       5
    Alex        7       7       8
    Ann         7       6       9

Para selecionar uma ou mais colunas por nome:

    df[['Test_1','Test_3']]

           Test_1  Test_3
    Jane        1       5
    Peter       5       5
    Alex        7       8
    Ann         7       9

Você também pode usar:

    df.Test_2

E você recebe coluna Test_2

    Jane     2
    Peter    4
    Alex     7
    Ann      6

Você também pode selecionar colunas e linhas dessas linhas usando .loc(). Isso é chamado de "fatiar" . Observe que eu passo da coluna Test_1paraTest_3

    df.loc[:,'Test_1':'Test_3']

A "fatia" é:

            Test_1  Test_2  Test_3
     Jane        1       2       5
     Peter       5       4       5
     Alex        7       7       8
     Ann         7       6       9

E se você quiser Petere Annde colunas Test_1e Test_3:

    df.loc[['Peter', 'Ann'],['Test_1','Test_3']]

Você obtém:

           Test_1  Test_3
    Peter       5       5
    Ann         7       9

8

Se você deseja obter um elemento pelo índice de linha e nome da coluna, pode fazê-lo exatamente como df['b'][0]. É tão simples quanto você pode imaginar.

Ou você pode usar o df.ix[0,'b']uso misto de índice e rótulo.

Nota: Desde que a v0.20 ixfoi descontinuada em favor de loc/ iloc.


6

Uma abordagem diferente e fácil: iterar linhas

usando iterows

 df1= pd.DataFrame() #creating an empty dataframe
 for index,i in df.iterrows():
    df1.loc[index,'A']=df.loc[index,'A']
    df1.loc[index,'B']=df.loc[index,'B']
    df1.head()

5
Por favor, não recomende o uso de iterrows (). É um habilitador flagrante do pior anti-padrão da história dos pandas.
cs95

Você poderia explicar o que você quer dizer com "pior anti-padrão"?
Ankita

1
IMHO, iterrows () deve ser a última opção ao usar pandas.
Elf

5

As diferentes abordagens discutidas nas respostas acima são baseadas no pressuposto de que o usuário sabe que os índices das colunas devem ser excluídos ou subconjuntos ou que deseja subconjunto de um quadro de dados usando um intervalo de colunas (por exemplo, entre 'C': 'E') . pandas.DataFrame.drop () é certamente uma opção para subconjunto de dados com base em uma lista de colunas definidas pelo usuário (embora você precise ser cauteloso ao usar sempre a cópia do dataframe e os parâmetros do local não devem ser configurados como True !!)

Outra opção é usar pandas.columns.difference () , que faz uma diferença definida nos nomes das colunas e retorna um tipo de índice de matriz que contém as colunas desejadas. A seguir está a solução:

df = pd.DataFrame([[2,3,4],[3,4,5]],columns=['a','b','c'],index=[1,2])
columns_for_differencing = ['a']
df1 = df.copy()[df.columns.difference(columns_for_differencing)]
print(df1)

A saída seria: b c 1 3 4 2 4 5


1
A cópia () não é necessária. ou seja: df1 = df[df.columns.difference(columns_for_differencing)]retornará um quadro de dados novo / copiado. Você poderá modificar df1sem alterar df. Obrigado, aliás. Era exatamente disso que eu precisava.
Bazyli Debowski 08/08/19

4

você também pode usar df.pop ()

>>> df = pd.DataFrame([('falcon', 'bird',    389.0),
...                    ('parrot', 'bird',     24.0),
...                    ('lion',   'mammal',   80.5),
...                    ('monkey', 'mammal', np.nan)],
...                   columns=('name', 'class', 'max_speed'))
>>> df
     name   class  max_speed
0  falcon    bird      389.0
1  parrot    bird       24.0
2    lion  mammal       80.5
3  monkey  mammal 

>>> df.pop('class')
0      bird
1      bird
2    mammal
3    mammal
Name: class, dtype: object

>>> df
     name  max_speed
0  falcon      389.0
1  parrot       24.0
2    lion       80.5
3  monkey        NaN

deixe-me saber se isso ajuda para você, use df.pop (c)


3

Eu já vi várias respostas sobre isso, mas permaneceu incerto para mim. Como você selecionaria essas colunas de interesse? A resposta para isso é que, se você os tiver reunido em uma lista, poderá fazer referência às colunas usando a lista.

Exemplo

print(extracted_features.shape)
print(extracted_features)

(63,)
['f000004' 'f000005' 'f000006' 'f000014' 'f000039' 'f000040' 'f000043'
 'f000047' 'f000048' 'f000049' 'f000050' 'f000051' 'f000052' 'f000053'
 'f000054' 'f000055' 'f000056' 'f000057' 'f000058' 'f000059' 'f000060'
 'f000061' 'f000062' 'f000063' 'f000064' 'f000065' 'f000066' 'f000067'
 'f000068' 'f000069' 'f000070' 'f000071' 'f000072' 'f000073' 'f000074'
 'f000075' 'f000076' 'f000077' 'f000078' 'f000079' 'f000080' 'f000081'
 'f000082' 'f000083' 'f000084' 'f000085' 'f000086' 'f000087' 'f000088'
 'f000089' 'f000090' 'f000091' 'f000092' 'f000093' 'f000094' 'f000095'
 'f000096' 'f000097' 'f000098' 'f000099' 'f000100' 'f000101' 'f000103']

Eu tenho a seguinte lista / matriz numpy extracted_features, especificando 63 colunas. O conjunto de dados original tem 103 colunas e eu gostaria de extrair exatamente essas, então eu usaria

dataset[extracted_features]

E você vai acabar com isso

insira a descrição da imagem aqui

Isso é algo que você usaria com frequência no Machine Learning (mais especificamente, na seleção de recursos). Eu gostaria de discutir outras maneiras também, mas acho que isso já foi coberto por outros stackoverflowers. Espero que isso tenha sido útil!


2

Você pode usar o pandas.DataFrame.filtermétodo para filtrar ou reordenar colunas como esta:

df1 = df.filter(['a', 'b'])

0
df[['a','b']] # select all rows of 'a' and 'b'column 
df.loc[0:10, ['a','b']] # index 0 to 10 select column 'a' and 'b'
df.loc[0:10, ['a':'b']] # index 0 to 10 select column 'a' to 'b'
df.iloc[0:10, 3:5] # index 0 to 10 and column 3 to 5
df.iloc[3, 3:5] # index 3 of column 3 to 5
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.