2 votes

Réorganisation des données superflues dans pandas

J'ai un dataframe organisé comme suit...

**Name** | **Mealtime** | **Food**  
John | 8:00 am | cereal  
John | 1:00 pm | salad  
John | 6:00 pm | pasta  
Sara | 8:00 am | yogurt  
Sara | 1:00 pm | panini  
Sara | 6:00 pm | steak  
Jake | 8:00 am | coffee  
Jake | 1:00 pm | burrito  
Jake | 6:00 pm | salad

Et j'ai besoin qu'il soit organisé comme suit

____| 8:00 am | 1:00 pm | 6:00 pm  
John | cereal | salad | pasta  
Sara | yogurt | panini | steak  
Jake | coffee | burrito | salad

Comment dois-je m'y prendre ? Notez que je ne recherche pas un changement esthétique. En fin de compte, j'aimerais sélectionner des lignes de données pour les introduire dans une boucle "for" de manière à ce que le nom puisse être déterminé à partir de l'entrée spécifique de l'aliment. Par exemple, si j'ai sélectionné la colonne "13h00", "salade" me renverra à John. Mais si j'avais saisi la colonne "18 heures", "salade" me dirigerait vers Jake.

4voto

coldspeed Points 111053

Vous avez besoin df.pivot :

In [606]: df.pivot(index='Name', columns='Mealtime', values='Food')
Out[606]: 
Mealtime  1:00 pm 6:00 pm 8:00 am
Name                             
Jake      burrito   salad  coffee
John        salad   pasta  cereal
Sara       panini   steak  yogurt

3voto

piRSquared Points 159

Option 0
numpy trancher avec pd.factorize

Je vais utiliser pd.factorize pour produire des valeurs entières pour chaque 'Name' y 'Mealtime' . Parallèlement, j'obtiens également les valeurs uniques. Chaque valeur entière finit par correspondre à l'élément qui se trouve à cette position entière dans le tableau des valeurs uniques.

Je connais maintenant le nombre de noms uniques et d'heures de repas uniques, ce qui me permet de connaître la taille de mon éventuel tableau pivoté. Je crée donc un tableau vide qui attendra que des valeurs lui soient attribuées.

Puisque j'ai factorisé et que les facteurs sont des positions entières, je peux les utiliser pour découper mon tableau vide à des fins d'affectation... c'est ce que je fais. Enfin, j'assemble le tout avec un nouveau dataframe brillant.

fn, un = pd.factorize(df.Name.values)
fm, um = pd.factorize(df.Mealtime.values)
v = np.empty((un.size, um.size), dtype=object)
v[fn, fm] = df.Food.values
pd.DataFrame(v, un, um)

     8:00 am  1:00 pm 6:00 pm
John  cereal    salad   pasta
Sara  yogurt   panini   steak
Jake  coffee  burrito   salad

Option 1
Utilisation set_index / unstack

df.set_index(['Name', 'Mealtime']).Food.unstack()

Mealtime  1:00 pm 6:00 pm 8:00 am
Name                             
Jake      burrito   salad  coffee
John        salad   pasta  cereal
Sara       panini   steak  yogurt

Option 2
Utilisation defaultdict

from collections import defaultdict

d = defaultdict(dict)
[d[m].setdefault(n, f) for n, m, f in df.values];
pd.DataFrame(d)

      1:00 pm 6:00 pm 8:00 am
Jake  burrito   salad  coffee
John    salad   pasta  cereal
Sara   panini   steak  yogurt

Option 3
Force brute

out = pd.DataFrame(index=df.Name.unique(), columns=df.Mealtime.unique())
[out.set_value(n, m, f) for n, m, f in df.values]
out

     8:00 am  1:00 pm 6:00 pm
John  cereal    salad   pasta
Sara  yogurt   panini   steak
Jake  coffee  burrito   salad

Calendrier
Conclusion : utiliser pivot pour des données plus importantes avec pandas pur. Il est difficile de faire mieux que sa simplicité et sa capacité à faire le travail dans ce scénario. Mais si vous voulez pivoter à une vitesse effrénée, essayez Option 0 .

%%timeit
fn, un = pd.factorize(df.Name.values)
fm, um = pd.factorize(df.Mealtime.values)
v = np.empty((un.size, um.size), dtype=object)
v[fn, fm] = df.Food.values
pd.DataFrame(v, un, um)

%timeit df.set_index(['Name', 'Mealtime']).Food.unstack()
%timeit df.pivot('Name', 'Mealtime', 'Food')
%timeit d = defaultdict(dict); [d[m].setdefault(n, f) for n, m, f in df.values]; pd.DataFrame(d)
%timeit out = pd.DataFrame(index=df.Name.unique(), columns=df.Mealtime.unique()); [out.set_value(n, m, f) for n, m, f in df.values]; out

Petites données

1000 loops, best of 3: 300 µs per loop
1000 loops, best of 3: 1.82 ms per loop
1000 loops, best of 3: 1.11 ms per loop
1000 loops, best of 3: 541 µs per loop
1000 loops, best of 3: 656 µs per loop

Données plus importantes

from string import ascii_letters

foods = np.array([
    'cereal', 'salad', 'pasta', 'yogurt',
    'panini', 'steak', 'coffee', 'burrito'
], dtype=object)
times = pd.date_range(
    pd.datetime.now().date(), periods=24, freq='H'
).strftime('%-I:00 %p')
names = list(ascii_letters)

idx = pd.MultiIndex.from_product([names, times], names=['Name', 'Mealtime'])
df = pd.DataFrame(dict(
    Food=np.random.choice(foods, idx.size),
), idx).reset_index()

1000 loops, best of 3: 383 µs per loop
1000 loops, best of 3: 1.99 ms per loop
1000 loops, best of 3: 1.34 ms per loop
100 loops, best of 3: 2.78 ms per loop
100 loops, best of 3: 6.6 ms per loop

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X