Como pegar fatias de coluna do dataframe nos pandas


264

Carrego alguns dados de aprendizado de máquina de um arquivo CSV. As duas primeiras colunas são observações e as colunas restantes são recursos.

Atualmente, faço o seguinte:

data = pandas.read_csv('mydata.csv')

o que dá algo como:

data = pandas.DataFrame(np.random.rand(10,5), columns = list('abcde'))

Eu gostaria de cortar esta trama de dados em duas dataframes: um contendo as colunas ae be um contendo as colunas c, de e.

Não é possível escrever algo como

observations = data[:'c']
features = data['c':]

Não sei ao certo qual é o melhor método. Eu preciso de um pd.Panel?

A propósito, acho a indexação do quadro de dados bastante inconsistente: data['a']é permitido, mas data[0]não é. Por outro lado, data['a':]não é permitido, mas data[0:]é. Existe uma razão prática para isso? Isso é realmente confuso se as colunas são indexadas por Int, já quedata[0] != data[0:1]


3
O DataFrame é inerentemente um objeto semelhante a um ditado quando você faz df, [...] no entanto, algumas conveniências, por exemplo, df[5:10]foram adicionadas para a seleção de linhas ( pandas.pydata.org/pandas-docs/stable/… )
— Wes McKinney

1
Então, o que essa inconsistência é uma decisão de design em favor da conveniência? Tudo bem, mas definitivamente precisa ser mais explícito para iniciantes!
— Cpa

3
A consideração de design da conveniência de suporte torna a curva de aprendizado muito acentuada. Eu gostaria que houvesse uma documentação melhor para o começo, apenas apresentando uma interface consistente. Por exemplo, concentre-se apenas na interface ix.
— Yu Shen

Respostas:


243

Resposta 2017 - pandas 0,20: .ix está obsoleto. Use .loc

Veja a reprovação nos documentos

.locusa indexação baseada em rótulo para selecionar linhas e colunas. Os rótulos são os valores do índice ou das colunas. Fatiar com .locinclui o último elemento.

Vamos supor que temos uma trama de dados com as seguintes colunas:
foo, bar, quz, ant, cat, sat, dat.

# selects all rows and all columns beginning at 'foo' up to and including 'sat'
df.loc[:, 'foo':'sat']
# foo bar quz ant cat sat

.locaceita a mesma notação de fatia que as listas Python fazem para linhas e colunas. Notação de fatia sendostart:stop:step

# slice from 'foo' to 'cat' by every 2nd column
df.loc[:, 'foo':'cat':2]
# foo quz cat

# slice from the beginning to 'bar'
df.loc[:, :'bar']
# foo bar

# slice from 'quz' to the end by 3
df.loc[:, 'quz'::3]
# quz sat

# attempt from 'sat' to 'bar'
df.loc[:, 'sat':'bar']
# no columns returned

# slice from 'sat' to 'bar'
df.loc[:, 'sat':'bar':-1]
sat cat ant quz bar

# slice notation is syntatic sugar for the slice function
# slice from 'quz' to the end by 2 with slice function
df.loc[:, slice('quz',None, 2)]
# quz cat dat

# select specific columns with a list
# select columns foo, bar and dat
df.loc[:, ['foo','bar','dat']]
# foo bar dat

Você pode cortar por linhas e colunas. Por exemplo, se você tem 5 linhas com rótulos v, w, x, y,z

# slice from 'w' to 'y' and 'foo' to 'ant' by 3
df.loc['w':'y', 'foo':'ant':3]
#    foo ant
# w
# x
# y

se você estiver usando apply com lambda row, como em: df['newcol'] = df.apply(lambda row: myfunc(row), axis=1) então você pode myfunc(row){... use row['foo':'ant']. por exemplo (de acordo com esta resposta do StackOverflow ), dentro de myfuncvocê pode avaliar se algum deles não é numérico:row['foo':'ant'].apply(lambda x: isinstance(x, str)).any()
— pashute

4
.ilocdeve ser usado agora, em vez de .loc. Corrija isso, e eu vou votar.
— craned

1
@craned - isso não está correto. Na documentação do Pandas: .loc é principalmente baseado em rótulo, mas também pode ser usado com uma matriz booleana. .loc aumentará KeyError quando os itens não forem encontrados. Uma declaração semelhante é feita sobre .iloc, exceto se refere especificamente à fatia baseada em índice. Em outras palavras, neste exemplo, ele usou a indexação baseada em rótulo e .loc é a escolha correta (basicamente a única opção). Se você deseja dividir por posição - linhas 5:10, por exemplo, use .iloc
— user2103050

149

Nota: .ix está obsoleto desde o Pandas v0.20. Você deve usar .locou .iloc, conforme apropriado.

O índice DataFrame.ix é o que você deseja acessar. É um pouco confuso (eu concordo que a indexação do Pandas às vezes é desconcertante!), Mas o seguinte parece fazer o que você deseja:

>>> df = DataFrame(np.random.rand(4,5), columns = list('abcde'))
>>> df.ix[:,'b':]
      b         c         d         e
0  0.418762  0.042369  0.869203  0.972314
1  0.991058  0.510228  0.594784  0.534366
2  0.407472  0.259811  0.396664  0.894202
3  0.726168  0.139531  0.324932  0.906575

onde .ix [fatia de linha, fatia de coluna] é o que está sendo interpretado. Mais sobre a indexação do Pandas aqui: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-advanced


5
Cuidadoso que varia em pandas incluem ambos os pontos finais, ou seja>>>data.ix[:, 'a':'c'] a b c 0 0.859192 0.881433 0.843624 1 0.744979 0.427986 0.177159
— gafanhoto

21
Várias colunas da cabine passam assim:df.ix[:,[0,3,4]]
— user602599

3
@ Karmel: Parece um erro de copiar / colar na saída acima. Talvez você quis dizer df.ix[:,'b':'e']?
— ChaimG

6
É melhor usar locem vez de ix: stackoverflow.com/a/31593712/4323
— John Zwinck

5
Respostas antigas como essa precisam ser excluídas. .ix está obsoleto e nunca deve ser usado.
— Ted Petrou

75

Vamos usar o conjunto de dados titânico do pacote seaborn como um exemplo

# Load dataset (pip install seaborn)
>> import seaborn.apionly as sns
>> titanic = sns.load_dataset('titanic')

usando os nomes das colunas

>> titanic.loc[:,['sex','age','fare']]

usando os índices da coluna

>> titanic.iloc[:,[2,3,6]]

using ix (Mais antigo que o Pandas <.20 versão)

>> titanic.ix[:,[‘sex’,’age’,’fare’]]

ou

>> titanic.ix[:,[2,3,6]]

usando o método reindex

>> titanic.reindex(columns=['sex','age','fare'])

6
Nos pandas 0,20: .ixestá obsoleto.
— Shihe Zhang

aviso de Passing list-likes to .loc or [] with any missing label will raise KeyError in the future, you can use .reindex() as an alternative.df.loc[:, some_list_of_columns]
— reprovação

35

Além disso, dado um DataFrame

dados

como no seu exemplo, se você deseja extrair apenas as colunas a e d (da 1ª e da 4ª coluna), o iloc mothod do quadro de dados do pandas é o que você precisa e pode ser usado com muita eficiência. Tudo o que você precisa saber é o índice das colunas que deseja extrair. Por exemplo:

>>> data.iloc[:,[0,3]]

Darei à você

          a         d
0  0.883283  0.100975
1  0.614313  0.221731
2  0.438963  0.224361
3  0.466078  0.703347
4  0.955285  0.114033
5  0.268443  0.416996
6  0.613241  0.327548
7  0.370784  0.359159
8  0.692708  0.659410
9  0.806624  0.875476

25

Você pode dividir as colunas de a DataFrameconsultando os nomes de cada coluna em uma lista, da seguinte maneira:

data = pandas.DataFrame(np.random.rand(10,5), columns = list('abcde'))
data_ab = data[list('ab')]
data_cde = data[list('cde')]

Portanto, se eu quiser todos os dados começando na coluna 'b', preciso encontrar o índice de 'b' em data.columns e fazer data [data.columns [1:]]? Essa é a maneira canônica de operar?
— Cpa

1
Quer dizer que você deseja selecionar todas as colunas de 'b' em diante?
— Brendan Wood

Sim ou selecionando todas as colunas em um determinado intervalo.
— Cpa

Eu sou muito novo em pandas, então não posso falar sobre o que é considerado canônico. Eu faria isso como você disse, mas use a get_locfunção data.columnspara determinar o índice da coluna 'b' ou qualquer outra coisa.
— Brendan Wood

20

E se você veio aqui procurando fatiar duas faixas de colunas e combiná-las (como eu), pode fazer algo como

op = df[list(df.columns[0:899]) + list(df.columns[3593:])]
print op

Isso criará um novo quadro de dados com as primeiras 900 colunas e (todas) colunas> 3593 (supondo que você tenha cerca de 4000 colunas no seu conjunto de dados).


Ótimo, alguém já tentou isso ... Eu estava pensando, esse 0: 899 que obtém as primeiras 900 colunas .. por que eles fizeram assim? Isso não parece o Python. Ao usar faixas em python é sempre 'até' não 'até e incluídos'
— zwep

14

Veja como você pode usar métodos diferentes para fatiar seletivamente as colunas, incluindo o rótulo seletivo, o índice e o intervalo seletivo.

In [37]: import pandas as pd    
In [38]: import numpy as np
In [43]: df = pd.DataFrame(np.random.rand(4,7), columns = list('abcdefg'))

In [44]: df
Out[44]: 
          a         b         c         d         e         f         g
0  0.409038  0.745497  0.890767  0.945890  0.014655  0.458070  0.786633
1  0.570642  0.181552  0.794599  0.036340  0.907011  0.655237  0.735268
2  0.568440  0.501638  0.186635  0.441445  0.703312  0.187447  0.604305
3  0.679125  0.642817  0.697628  0.391686  0.698381  0.936899  0.101806

In [45]: df.loc[:, ["a", "b", "c"]] ## label based selective column slicing 
Out[45]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

In [46]: df.loc[:, "a":"c"] ## label based column ranges slicing 
Out[46]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

In [47]: df.iloc[:, 0:3] ## index based column ranges slicing 
Out[47]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

### with 2 different column ranges, index based slicing: 
In [49]: df[df.columns[0:1].tolist() + df.columns[1:3].tolist()]
Out[49]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

Tente evitar apenas descartar o código como resposta e tente explicar o que ele faz e por quê. Seu código pode não ser óbvio para pessoas que não têm a experiência de codificação relevante. Edite sua resposta para incluir esclarecimentos, contexto e tente mencionar quaisquer limitações, suposições ou simplificações em sua resposta.
— Sᴀᴍ Onᴇᴌᴀ

1

Seu equivalente

 >>> print(df2.loc[140:160,['Relevance','Title']])
 >>> print(df2.ix[140:160,[3,7]])

1

se o quadro de dados for assim:

group         name      count
fruit         apple     90
fruit         banana    150
fruit         orange    130
vegetable     broccoli  80
vegetable     kale      70
vegetable     lettuce   125

e OUTPUT pode ser como

   group    name  count
0  fruit   apple     90
1  fruit  banana    150
2  fruit  orange    130

se você usar o operador lógico np.logical_not

df[np.logical_not(df['group'] == 'vegetable')]

mais sobre

https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.logic.html

outros operadores lógicos

  1. logic_and (x1, x2, / [, out, where, ...]) Calcule o valor de verdade de x1 AND x2 em termos de elementos.

  2. logic_or (x1, x2, / [, out, where, casting, ...]) Calcule o valor de verdade de x1 OR x2 em termos de elementos.

  3. logic_not (x, / [, out, where, casting, ...]) Calcule o valor de verdade de NOT x em termos de elementos.
  4. logic_xor (x1, x2, / [, fora, onde, ..]) Calcule o valor de verdade de x1 XOR x2, em elementos.

0

Outra maneira de obter um subconjunto de colunas da trama de dados, supondo que você quer todas as linhas, seria fazer:
data[['a','b']]e data[['c','d','e']]
Se você quiser usar índices de coluna numéricos que você pode fazer:
data[data.columns[:2]]edata[data.columns[2:]]

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.