Comment prendre des tranches de colonne de trame de données dans les pandas


264

Je charge des données d'apprentissage automatique à partir d'un fichier CSV. Les 2 premières colonnes sont des observations et les colonnes restantes sont des caractéristiques.

Actuellement, je fais ce qui suit:

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

ce qui donne quelque chose comme:

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

Je voudrais découper cette trame de données en deux trames de données: une contenant les colonnes aet bet l'autre contenant les colonnes c, det e.

Il n'est pas possible d'écrire quelque chose comme

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

Je ne sais pas quelle est la meilleure méthode. Ai-je besoin d'un pd.Panel?

Soit dit en passant, je trouve que l'indexation des trames de données est assez incohérente: data['a']est autorisée, mais data[0]ne l'est pas. De l'autre côté, data['a':]n'est pas autorisé mais l' data[0:]est. Y a-t-il une raison pratique à cela? C'est vraiment déroutant si les colonnes sont indexées par Int, étant donné quedata[0] != data[0:1]


3
DataFrame est intrinsèquement un objet de type dict lorsque vous faites df, [...] cependant certaines commodités, par exemple df[5:10]ont été ajoutées pour sélectionner des lignes ( pandas.pydata.org/pandas-docs/stable/… )
Wes McKinney

1
Alors, quelle est cette incohérence est une décision de conception en faveur de la commodité? D'accord, mais cela doit certainement être plus explicite pour les débutants!
cpa

3
La considération de conception de la commodité du support rend la courbe d'apprentissage beaucoup plus raide. Je souhaite qu'il y ait une meilleure documentation pour le début présentant simplement une interface cohérente. Par exemple, concentrez-vous uniquement sur l'interface ix.
Yu Shen

Réponses:


243

Réponse 2017 - pandas 0.20: .ix est déconseillé. Utilisez .loc

Voir la dépréciation dans la documentation

.locutilise l'indexation basée sur les étiquettes pour sélectionner à la fois les lignes et les colonnes. Les étiquettes étant les valeurs de l'index ou des colonnes. Le découpage avec .locinclut le dernier élément.

Supposons que nous avons une trame de données avec les colonnes suivantes:
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

.locaccepte la même notation de tranche que les listes Python pour les lignes et les colonnes. Notation de tranche étantstart: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

Vous pouvez découper par lignes et colonnes. Par exemple, si vous avez 5 lignes avec des étiquettes 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

si votre utilisation s'applique avec la ligne lambda, comme dans: df['newcol'] = df.apply(lambda row: myfunc(row), axis=1) alors vous pouvez en myfunc(row){... utiliser row['foo':'ant']. par exemple (selon cette réponse StackOverflow ), à l'intérieur du myfuncvous pouvez évaluer si l'un d'eux n'est pas numérique:row['foo':'ant'].apply(lambda x: isinstance(x, str)).any()
pashute

4
.ilocdevrait être utilisé maintenant, au lieu de .loc. Réparez cela, et je vais le voter.
grue

1
@craned - ce n'est pas correct. D'après la documentation Pandas: .loc est principalement basé sur une étiquette, mais peut également être utilisé avec un tableau booléen. .loc lève KeyError lorsque les éléments ne sont pas trouvés. Une déclaration similaire est faite à propos de .iloc sauf qu'elle se réfère spécifiquement au découpage basé sur un index. En d'autres termes, dans cet exemple, il a utilisé l'indexation basée sur les étiquettes et .loc est le bon choix (essentiellement le seul choix). Si vous voulez couper par position -rows 5:10 par exemple, alors utilisez .iloc
user2103050

149

Remarque: .ix est obsolète depuis Pandas v0.20. Vous devez plutôt utiliser .locou .iloc, selon le cas.

L'index DataFrame.ix est ce à quoi vous souhaitez accéder. C'est un peu déroutant (je suis d'accord que l'indexation Pandas est parfois déroutante!), Mais ce qui suit semble faire ce que vous voulez:

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

où .ix [tranche de ligne, tranche de colonne] est ce qui est interprété. Plus d'informations sur l'indexation des pandas ici: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-advanced


5
Attention que les gammes dans les pandas incluent les deux extrémités, c'est>>>data.ix[:, 'a':'c'] a b c 0 0.859192 0.881433 0.843624 1 0.744979 0.427986 0.177159
sauterelle

21
Plusieurs colonnes peuvent être passées comme cecidf.ix[:,[0,3,4]]
user602599

3
@Karmel: Il semble qu'une erreur de copier / coller dans la sortie ci-dessus. Peut-être que vous vouliez dire df.ix[:,'b':'e']?
ChaimG

6
Il vaut mieux utiliser à la locplace de ix: stackoverflow.com/a/31593712/4323
John Zwinck

5
Les anciennes réponses comme celle-ci doivent être supprimées. .ix est obsolète et ne doit jamais être utilisé.
Ted Petrou

75

Permet d'utiliser le jeu de données titanesque du package seaborn comme exemple

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

en utilisant les noms de colonne

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

en utilisant les indices de colonne

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

en utilisant ix (plus ancien que la version Pandas <.20)

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

ou

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

en utilisant la méthode de réindexation

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

6
Chez les pandas 0,20: .ixest obsolète.
Shihe Zhang

avertissement de dépréciation: Passing list-likes to .loc or [] with any missing label will raise KeyError in the future, you can use .reindex() as an alternative.lorsque vous utilisezdf.loc[:, some_list_of_columns]
Marc Maxmeister

35

En outre, étant donné un DataFrame

Les données

comme dans votre exemple, si vous souhaitez extraire uniquement les colonnes a et d (ei la 1ère et la 4ème colonne), iloc mothod de la base de données pandas est ce dont vous avez besoin et pourrait être utilisé très efficacement. Tout ce que vous devez savoir, c'est l'index des colonnes que vous souhaitez extraire. Par exemple:

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

te donnera

          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

Vous pouvez découper les colonnes d'un DataFrameen vous référant aux noms de chaque colonne d'une liste, comme ceci:

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

Donc, si je veux toutes les données à partir de la colonne 'b', je dois trouver l'index de 'b' dans data.columns et faire des données [data.columns [1:]]? C'est la manière canonique de fonctionner?
cpa

1
Vous voulez dire que vous voulez sélectionner toutes les colonnes à partir de 'b'?
Brendan Wood

Oui, ou en sélectionnant toutes les colonnes d'une plage donnée.
cpa

Je suis moi-même assez nouveau pour les pandas, donc je ne peux pas parler de ce qui est considéré comme canonique. Je le ferais comme vous l'avez dit, mais utilisez la get_locfonction on data.columnspour déterminer l'indice de la colonne «b» ou autre chose.
Brendan Wood

20

Et si vous êtes venu ici à la recherche de deux tranches de colonnes et de les combiner (comme moi), vous pouvez faire quelque chose comme

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

Cela créera une nouvelle trame de données avec 900 premières colonnes et (toutes) colonnes> 3593 (en supposant que vous avez environ 4000 colonnes dans votre ensemble de données).


Génial, quelqu'un a essayé ça ... Je me demandais, ce 0: 899 qui obtient les 900 premières colonnes .. pourquoi l'ont-ils fait comme ça? Cela ne ressemble pas du tout à Python. Lors de l'utilisation de plages en python, il est toujours 'jusqu'à' pas 'jusqu'à et inclus'
zwep

14

Voici comment vous pouvez utiliser différentes méthodes pour effectuer un découpage de colonne sélectif, notamment un découpage de colonne basé sur une étiquette sélective, un index et une plage sélective.

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

S'il vous plaît essayez d'éviter de simplement vider le code comme réponse et essayez d'expliquer ce qu'il fait et pourquoi. Votre code peut ne pas être évident pour les personnes n'ayant pas l'expérience de codage appropriée. Veuillez modifier votre réponse pour inclure des clarifications, du contexte et essayer de mentionner toute limitation, hypothèse ou simplification dans votre réponse.
Sᴀᴍ Onᴇᴌᴀ

1

Son équivalent

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

1

si la trame de données ressemble à ça:

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

et OUTPUT pourrait être comme

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

si vous utilisez l'opérateur logique np.logical_not

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

plus à propos

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

autres opérateurs logiques

  1. logic_and (x1, x2, / [, out, where, ...]) Calculez la valeur de vérité de x1 ET x2 élément par élément.

  2. logic_or (x1, x2, / [, out, where, casting, ...]) Calculez la valeur de vérité de x1 OU x2 élément par élément.

  3. logic_not (x, / [, out, where, casting, ...]) Calculez la valeur de vérité de NOT x par élément.
  4. logic_xor (x1, x2, / [, out, where, ..]) Calculez la valeur de vérité de x1 XOR x2, élément par élément.

0

Une autre façon d'obtenir un sous-ensemble de colonnes à partir de votre DataFrame, en supposant que vous voulez toutes les lignes, serait de faire:
data[['a','b']]et data[['c','d','e']]
si vous souhaitez utiliser des index de colonnes numériques, vous pouvez le faire:
data[data.columns[:2]]etdata[data.columns[2:]]

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.