2017-09-07 1 views
3

Pourquoi .loc ne renvoie qu'une seule ligne où plusieurs lignes ont le même MultiIndex?Incohérence entre les pandas xs et loc pour les indices répétés

Compte tenu de la trame de données suivante

  col0  col1 col2 
idx0 idx1 
0 0  1.0 example1 1.0 
    0  4.0 example2 8.0 
    1  9.0 example3 27.0 
    1  16.0 example4 64.0 
1 0  0.5 example1 0.5 
    0  2.0 example2 4.0 
    1  4.5 example3 13.5 
    1  8.0 example4 32.0 

l'opération .xs sélectionnera

In [121]: df.xs((0,1), level=[0,1]) 
Out[121]: 
      col0  col1 col2 
idx0 idx1 
0 1  9.0 example3 27.0 
    1  16.0 example4 64.0 

alors que l'opération .loc sélectionnera

In [125]: df.loc[[(0,1)]] 
Out[125]: 
      col0  col1 col2 
idx0 idx1 
0 1  16.0 example4 64.0 

Ceci est souligné encore par le

suivant
In [149]: df.loc[pd.IndexSlice[:, 1], :] 
Out[149]: 
      col0  col1 col2 
idx0 idx1 
0 1  9.0 example3 27.0 
    1  16.0 example4 64.0 

In [150]: df.loc[pd.IndexSlice[0, 1], :] 
Out[150]: 
col0   16 
col1 example4 
col2   64 
Name: (0, 1), dtype: object 

Set Up

import pandas as pd 
import numpy as np 
idx0 = range(2) 
idx1 = np.repeat(range(2), 2) 

midx = pd.MultiIndex(
    levels=[idx0, idx1], 
    labels=[ 
     np.repeat(range(len(idx0)), len(idx1)), 
     np.tile(range(len(idx1)), len(idx0)) 
    ], 
    names=['idx0', 'idx1'] 
) 

df = pd.DataFrame(
    [ 
     [i**2/float(j), 'example{}'.format(i), i**3/float(j)] 
     for j in range(1, len(idx0) + 1) 
     for i in range(1, len(idx1) + 1) 
    ], 
    columns=['col0', 'col1', 'col2'], 
    index=midx 
) 
+1

Cela est particulièrement inhabituel étant donné que, [avec un indice de base, 'loc' retournera toutes les instances de l'étiquette si vous avez des doublons.] (https://stackoverflow.com/a/45636490/7954504) –

+1

FYI: Si vous lancez l'index avec 'np.array' comme' dtype = int' a des problèmes donc ce n'est pas un problème avec les points flottants –

+1

Quelle version des pandas utilisez-vous? – Alexander

Répondre

1

En utilisant .xs

df.xs((0,1), level=[0,1]) 
Out[74]: 
      col0  col1 col2 
idx0 idx1      
0 1  9.0 example3 27.0 
    1  16.0 example4 64.0 

En utilisant .loc

df.loc[0].loc[1] 
Out[75]: 
     col0  col1 col2 
idx1      
1  9.0 example3 27.0 
1  16.0 example4 64.0 

Ajouter [] dans l'index secondaire: (PS: link)

df.loc[(0, [1]),:] 

Out[90]: 
      col0  col1 col2 
idx0 idx1      
0 1  9.0 example3 27.0 
    1  16.0 example4 64.0 
+0

Cela ne répond pas à la question vraiment ... Je suis une solution de contournement, je demande pourquoi '.loc [[(0,1)]]' ne fonctionne pas. Je vous remercie gentiment pour votre autre exemple, bien que cela semble juste souligner le comportement inattendu de '.loc [[(0,1)]]'! –

+0

@AlexanderMcFarlane J'ai mis à jour, sry, matin ... Vous savez .. – Wen

+2

pouvez-vous expliquer pourquoi le '[1]' est nécessaire? Cela semble assez arbitraire! –

1

Je ne crois pas que votre multi-index est créé correctement.

df = df.assign(
    idx0=[0] * 4 + [1] * 4, 
    idx1=[0, 0, 1, 1] * 2).set_index(['idx0', 'idx1']) 

En utilisant l'une des façons correctes d'utiliser loc pour accéder aux données:

>>> df.loc[(0, 1), :] 
      col0  col1 col2 
idx0 idx1      
0 1  9 example3 27 
    1  16 example4 64 

En utilisant la même commande sur la trame de données d'origine, je reçois: TypeError: only integer arrays with one element can be converted to an index.

MISE À JOUR

Comme je l'ai mentionné précédemment, vous ne semblez pas créer correctement votre multi-index. Cette base de données avec le multi-index correctement construit fonctionne comme prévu avec vos exemples (en utilisant un ancien pandas, v 0.17.2).

midx = pd.MultiIndex.from_product([[0, 1], [0, 0, 1, 1]], names=['idx0', 'idx1']) 
df = pd.DataFrame(
    [ 
     [i**2/float(j), 'example{}'.format(i), i**3/float(j)] 
     for j in range(1, len(idx0) + 1) 
     for i in range(1, len(idx1) + 1) 
    ], 
    columns=['col0', 'col1', 'col2'], 
    index=midx) 

En utilisant midx tel que défini ci-dessus:

>>> midx 
MultiIndex(levels=[[0, 1], [0, 1]], 
      labels=[[0, 0, 0, 0, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 1, 1]], 
      names=[u'idx0', u'idx1']) 

aide midx par votre définition:

>>> midx 
MultiIndex(levels=[[0, 1], [0, 0, 1, 1]], 
      labels=[[0, 0, 0, 0, 1, 1, 1, 1], [0, 1, 2, 3, 0, 1, 2, 3]], 
      names=[u'idx0', u'idx1']) 
+0

Le 'df' de la question a deux indices' int64', semble être créé "correctement". Pouvez-vous expliquer pourquoi cela se comporte comme prévu avec votre modification? –

+0

oui je suis tombé sur le même. Je vais rendre ma création 'MultiIndex' plus propre dans l'exemple ci-dessous. Je l'ai compacté pour rendre mon message plus court mais j'ai la même confusion que @BradSolomon –

+0

Merci pour la mise à jour. Ce problème est-il dû à l'existence de valeurs dupliquées dans le fichier 'levels' kwarg? Il semble que la lib de Pandas devrait peut-être lancer une erreur si les 'niveaux 'ne peuvent pas prendre des doublons? –