2015-12-15 1 views
2

J'aurais besoin de votre aide pour remodeler une base de données pandas. Je suis assez nouveau pour les pandas (déjà amoureux cependant) mais ce problème ne cesse de me faire peur.Date de remise en forme des Pandas, bacs groupés

Je travaille sur une étude environnementale, qui consiste à compter les voitures sur des itinéraires spécifiques, en prenant note de leur origine et destination et du nombre de passagers.

Le dataframe ressemblerait à ceci (sauf en réalité, il contient 10,000s de lignes)

df = pd.DataFrame(
    {'date':['20151201','20151202','20151203','20151204','20151204','20151205','20151206','20151207','20151210','20151211','20151212','20151225'], 
        'id':[123,234,543,890,543,123,234,543,123,123,123,890], 
        'event':[1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1], 
        'city':['AB','YU','CD','CD','YU','YU','BA','AB','CB','BA','CY','CC'], 
        'number of passengers':[1,5,1,20,1,1,5,10,2,25,3,20] 
    } 
) 

    city  date event id number of passengers 
0 AB 20151201  1 123      1 
1 YU 20151202  1 234      5 
2 CD 20151203  1 543      1 
3 CD 20151204  1 890     20 
4 YU 20151204  -1 543      1 
5 YU 20151205  -1 123      1 
6 BA 20151206  -1 234      5 
7 AB 20151207  -1 543     10 
8 CB 20151210  -1 123      2 
9 BA 20151211  -1 123     25 
10 CY 20151212  -1 123      3 
11 CC 20151225  -1 890     20 

où df [ 'événement'] est indiquant si la ville est d'origine (1) de la voiture ou de destination (- 1) . df ['id'] est un identifiant unique (plaque d'immatriculation) de voiture. Pour rendre les choses encore plus compliquées (au moins pour moi), il peut y avoir plusieurs observations de voitures remontant la même route, le même jour ou un autre jour et bien sûr les observations sont incomplètes (voiture retournée par exemple à l'origine inaperçue).

df.set_index(['id','date','event']).unstack('event').swaplevel(0,1,axis=1) 


event   -1 1     -1     1 
      city city number of passengers number of passengers 
id date               
123 20151201 NaN AB     NaN     1 
    20151205 YU NaN     1     NaN 
    20151210 CB NaN     2     NaN 
    20151211 BA NaN     25     NaN 
    20151212 CY NaN     3     NaN 
234 20151202 NaN YU     NaN     5 
    20151206 BA NaN     5     NaN 
543 20151203 NaN CD     NaN     1 
    20151204 YU NaN     1     NaN 
    20151207 AB NaN     10     NaN 
890 20151204 NaN CD     NaN     20 
    20151225 CC NaN     20     NaN 

Le but je pense, est de créer un dataframe qui montre tout le trafic en provenance d'une ville, sa destination et l'apparition d'observations du nombre de passagers (idéalement mis en cellule dans des catégories telles que « (1- 2), (3-5), (6-7), (> 7))

Idéalement, je me attends le résultat dataframe à ressembler à quelque chose comme ceci:

Origin Destination  0-2  3-5  6-7 >7 
AB YU    1  0  0  0 
     CB    1  0  0  0 
     BA    0  0  0  1 
     CY    0  1  0  0 
YU BA    0  2  0  0 
CD YU    1  2  0  0 
     AB    0  0  1  0 
     CC    0  0  0  1 

J'ai ajouté une origine et colonne de destination via

df['origin']= np.where(df['event'] == 1,df['city'],np.NAN) 
df['destination']= np.where(df['event'] == -1,df['city'],np.NAN) 

mais les prochaines étapes du remodelage me échapper. J'ai essayé quelques trucs avec le pivot des pandas et les pandas désemparés mais il semble que je manque quelque chose car rien de tout cela n'a fonctionné. Je suppose que je devrais aussi utiliser des pandas coupés à un moment donné pour le binning mais je n'ai pas réussi à atteindre ce stade dans mon analyse.

Seriez-vous capable de me diriger dans la bonne direction? Comment est-ce que je reformerais les données pour réaliser l'aperçu du trafic par origine?

+0

votre sortie ne correspond pas à votre saisie. S'il vous plaît fournir un exemple reproductible. –

+0

Excuses et merci de l'avoir signalé, Colonel Beauvel. J'ai édité la question pour fournir un exemple plus clair (j'espère). Merci encore. –

Répondre

0

Vous avez mes excuses les plus sincères parce que cela est difficile à suivre, donc si quelqu'un peut penser à un moyen plus facile, allez-y, mais là, vous allez:

df['number of passengers'] = pd.cut(df['number of passengers'], 
           bins=[0, 2, 5, 7, max(df['number of passengers']) + 1], 
           right=False) 

# Recode the factor levels for readable column labels when unstacked 
df.ix[df['event']==1, 'event'] = 'origin' 
df.ix[df['event']==-1, 'event'] = 'destination' 

# Split the DataFrame, unstack each factor, then join 
new_df = pd.DataFrame(
    df.groupby('id')['number of passengers'].value_counts() 
).unstack(
    'number of passengers' 
).fillna(0).join(
    df.set_index('id')[['city', 'date', 'event']].reset_index().set_index(
     ['id', 'date', 'event'] 
    ).unstack('event').reset_index(level='date', drop=True) 
).reset_index() 

# Flatten the column multiindex 
new_df.columns = new_df.columns.droplevel() 
new_df.columns = ['id', '[0, 2)', '[2, 5)', '[5, 7)', '> 7', 'destination', 'origin'] 

# If we don't do this, there will be separate rows for origins and destinations 
new_df['origin'] = new_df['origin'].fillna(method='ffill') 
new_df = new_df.dropna().set_index(['id', 'origin', 'destination'], drop=True) 

new_df = new_df.reset_index()[['origin', 'destination', '[0, 2)', '[2, 5)', '[5, 7)', '> 7']].set_index(['origin', 'destination']) 
new_df 

Vous donne ceci:

    [0, 2) [2, 5) [5, 7) > 7 
origin destination    
AB  YU   2  2  0  1 
     CB   2  2  0  1 
     BA   2  2  0  1 
     CY   2  2  0  1 
YU  BA   0  0  2  0 
CD  YU   2  0  0  1 
     AB   2  0  0  1 
     CC   0  0  0  2 
+0

remercie Adam pour votre réponse. Cependant lorsque je fais le suivi de votre code, j'obtiens une erreur "Niveau du nombre de passagers non trouvé" lors de l'exécution de la ligne new_df = pd.DataFrame (...). Une idée pourquoi? Très appréciée! –

+0

Non. Toujours fonctionne ici très bien. Peut-être que vous utilisez une ancienne version de pandas qui n'implémente pas l'une de ces méthodes? J'utilise 0.17.0. –