1
votes

Comment sélectionner plusieurs colonnes par nom qui ne sont pas adjacentes et combiner plusieurs méthodes de découpage?

Existe-t-il un moyen de sélectionner plusieurs colonnes qui ne sont pas adjacentes et de combiner plusieurs méthodes?

test dataframe:

frames = [test.loc[:, 'ID'],
          test.loc[:, test.columns.str.startswith('rfm')],
          test.loc[:, 'a':'c'],
          test.iloc[:, -1]]

test_sub = pd.concat(frames)

Disons que je veux les colonnes: ID, toutes les colonnes commençant par rfm, a: c et e . Dans cet ordre.

Je pensais que quelque chose de ce genre le ferait, mais je n'ai pas été en mesure de le faire fonctionner

test = pd.DataFrame(np.random.rand(3, 9),
                    columns=['ID', 'rfm_snittbeløp_gaver', 'rfm_maksbeløp_gaver', 'rfm_antall_kampanjer',
                             'a','b','c','d','e'])

J'ai lu qu'il réinitialise le index et que je ne pourrai pas contrôler l'ordre des colonnes.

De préférence, il y aurait quelque chose comme np.r_ pour .loc pour combiner les tranches telles que trouvées dans cet article

  1. Sélection de colonnes non adjacentes par pandas de numéro de colonne

Mais je n'aime pas utiliser la position d'index quand je fais référence aux colonnes

Toute aide est très appréciée


1 commentaires

par a: c voulez-vous dire a, b, c inclus?


3 Réponses :


4
votes

voici une manière d'utiliser np.r_ et get_loc () et get_indexer () :

         ID  rfm_snittbeløp_gaver  rfm_maksbeløp_gaver  rfm_antall_kampanjer  \
0  0.822275              0.155649             0.189058              0.050138   
1  0.188038              0.286731             0.509774              0.171374   
2  0.626211              0.477937             0.585987              0.358124   

          a         b         c         e  
0  0.652142  0.492184  0.464453  0.361395  
1  0.242480  0.963673  0.898177  0.813195  
2  0.863088  0.781858  0.924203  0.690219  

test.iloc[:,np.r_[ID,rfm,a:c+1,e]]

ID= test.columns.get_loc('ID')
rfm=test.columns.get_indexer(test.columns[test.columns.str.startswith('rfm')])
a=test.columns.get_loc('a')
c=test.columns.get_loc('c')
e=test.columns.get_loc('e')


4 commentaires

C'était assez chouette, mais que se passerait-il si j'aurais voulu des colonnes de a: p, alors j'aurais besoin de créer beaucoup de get_locs ...


@Jon non, vous auriez encore besoin de seulement 2 get loc. a: c + 1 vous donne l'index de la plage de a à c, pour a: p remplacez c par p dans la solution


ah, je vois maintenant. Donc, avec juste une fonction personnalisée en plus de cela pour faire les get_locs, c'est génial. Ensuite, je peux simplement passer dans les colonnes que je veux et trancher et couper en dés à ma guise!


yep :) aussi cela résoudrait que vous n'aimiez pas utiliser la position d'index lorsque vous vous référez aux noms de colonnes. c'est une bonne fonctionnalité à avoir à ces fins.



3
votes

Vous êtes assez proche, avec axis=1:

frames = [test.loc[:, 'ID'],
          test.loc[:, test.columns.str.startswith('rfm')],
          test.loc[:, 'a':'c'],
          test.iloc[:, -1]]

test_sub = pd.concat(frames, axis=1)


0 commentaires

1
votes

Une approche plus générale sera de créer une classe comme la suivante:

0    0.129801
1    0.786684
2    0.839015
Name: ID, dtype: float64

Vous pourriez alors faire:

print(test.loc[:, s_(test.columns)['ID']])

Sortie

         ID  rfm_snittbeløp_gaver  ...         c         e
0  0.026803              0.603409  ...  0.819486  0.396006
1  0.791049              0.450502  ...  0.097529  0.708746
2  0.623558              0.513678  ...  0.140740  0.958713

[3 rows x 8 columns]

Notez que cela fonctionne également pour l'indexation simple:

columns = ['ID', 'rfm_snittbeløp_gaver', 'rfm_maksbeløp_gaver', 'rfm_antall_kampanjer', 'a', 'b', 'c', 'd', 'e']
test = pd.DataFrame(np.random.rand(3, 9), columns=columns)

print(test.loc[:, s_(test.columns)['ID', test.columns.str.startswith('rfm'), 'a':'c', -1]])

Sortie

class s_:
    """Create slices from given columns resembling numpy s_"""

    def __init__(self, cols):
        self.indices = pd.Series(cols, index=cols)

    def __getitem__(self, item):
        if isinstance(item, tuple):
            result = []
            for indexing in item:
                try:
                    if isinstance(indexing, str): # treat strings as labels
                        result.append(self.indices[indexing])
                    else:
                        result.extend(self.indices[indexing])
                except TypeError:
                    result.append(self.indices[indexing])
            return result
        else:
            return self.indices[item]


0 commentaires