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.

user1234440
fonte
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.

ely
fonte
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
...
ayhan
fonte
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.

fogão
fonte
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
Wes McKinney
fonte
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)
zerovector
fonte
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 .

Muthu Chithambara Jothi
fonte
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']]
Vivek Ananthan
fonte
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

Alvis
fonte
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

tozCSS
fonte
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
pink.slash
fonte
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.

W.Perrin
fonte
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()
Ankita
fonte
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

Harshit
fonte
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)

Puneet Sinha
fonte
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!

Kareem Jeiroudi
fonte
2

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

df1 = df.filter(['a', 'b'])
Ramin Melikov
fonte
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
Biplob Das
fonte