web-dev-qa-db-fra.com

obtenir les première et dernière valeurs dans un groupby

J'ai une trame de données df

df = pd.DataFrame(np.arange(20).reshape(10, -1),
                  [['a', 'a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'd'],
                   ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']],
                  ['X', 'Y'])

Comment obtenir les première et dernière lignes, groupées par le premier niveau de l'index?

J'ai essayé

df.groupby(level=0).agg(['first', 'last']).stack()

et j'ai

          X   Y
a first   0   1
  last    6   7
b first   8   9
  last   12  13
c first  14  15
  last   16  17
d first  18  19
  last   18  19

C'est tellement proche de ce que je veux. Comment puis-je conserver l'index de niveau 1 et l'obtenir à la place:

      X   Y
a a   0   1
  d   6   7
b e   8   9
  g  12  13
c h  14  15
  i  16  17
d j  18  19
  j  18  19
19
Brian

Option 1

def first_last(df):
    return df.ix[[0, -1]]

df.groupby(level=0, group_keys=False).apply(first_last)

enter image description here


Option 2 - ne fonctionne que si l'index est unique

idx = df.index.to_series().groupby(level=0).agg(['first', 'last']).stack()
df.loc[idx]

Option 3 - selon les notes ci-dessous, cela n'a de sens que lorsqu'il n'y a pas de NA

J'ai également abusé de la fonction agg. Le code ci-dessous fonctionne, mais est beaucoup plus laid.

df.reset_index(1).groupby(level=0).agg(['first', 'last']).stack() \
    .set_index('level_1', append=True).reset_index(1, drop=True) \
    .rename_axis([None, None])

Remarque

per @unutbu: agg(['first', 'last']) prend les premières valeurs non na.

J'ai interprété cela comme, il doit alors être nécessaire d'exécuter cette colonne par colonne. En outre, forcer le niveau d'index = 1 à s'aligner peut même ne pas avoir de sens.

Incluons un autre test

df = pd.DataFrame(np.arange(20).reshape(10, -1),
                  [list('aaaabbbccd'),
                   list('abcdefghij')],
                  list('XY'))

df.loc[Tuple('aa'), 'X'] = np.nan

def first_last(df):
    return df.ix[[0, -1]]

df.groupby(level=0, group_keys=False).apply(first_last)

enter image description here

df.reset_index(1).groupby(level=0).agg(['first', 'last']).stack() \
    .set_index('level_1', append=True).reset_index(1, drop=True) \
    .rename_axis([None, None])

enter image description here

Assez sur! Cette deuxième solution prend la première valeur valide dans la colonne X. Il est désormais absurde d'avoir forcé cette valeur à s'aligner sur l'index a.

15
piRSquared

Cela pourrait être une solution facile.

df.groupby(level = 0, as_index= False).nth([0,-1])

      X   Y
a a   0   1
  d   6   7
b e   8   9
  g  12  13
c h  14  15
  i  16  17
d j  18  19

J'espère que cela t'aides. (Y)

4
Akarsh Jain

Veuillez essayer ceci:

Pour la dernière valeur: df.groupby('Column_name').nth(-1),

Pour la première valeur: df.groupby('Column_name').nth(0)

0
nat23dip