2013-07-16 11 views
6

Individuali (indicizzati da 0 a 5) scegliere tra due posizioni: A e B. I miei dati hanno un ampio formato contenente caratteristiche che variano da individuo (ind_var) e caratteristiche che variano solo in base alla posizione (location_var).Complicato (per me) rimodellamento da largo a lungo in Panda

Per esempio, ho:

In [281]: 

df_reshape_test = pd.DataFrame({'location' : ['A', 'A', 'A', 'B', 'B', 'B'], 'dist_to_A' : [0, 0, 0, 50, 50, 50], 'dist_to_B' : [50, 50, 50, 0, 0, 0], 'location_var': [10, 10, 10, 14, 14, 14], 'ind_var': [3, 8, 10, 1, 3, 4]}) 

df_reshape_test 

Out[281]: 
    dist_to_A dist_to_B ind_var location location_var 
0 0   50    3 A  10 
1 0   50    8 A  10 
2 0   50   10 A  10 
3 50   0    1 B  14 
4 50   0    3 B  14 
5 50   0    4 B  14 

La 'location' variabile è quello scelto dal singolo. dist_to_A è la distanza alla posizione A dalla location scelta da parte dell'individuo (stessa cosa con dist_to_B)

vorrei i miei dati ad avere questa forma:

choice dist_S ind_var location location_var 
0 1  0  3   A   10 
0 0  50  3   B   14 
1 1  0  8   A   10 
1 0  50  8   B   14 
2 1  0  10   A   10 
2 0  50  10   B   14 
3 0  50  1   A   10 
3 1  0  1   B   14 
4 0  50  3   A   10 
4 1  0  3   B   14 
5 0  50  4   A   10 
5 1  0  4   B   14 

dove la scelta == 1 indica individuale ha scelto quella posizione e dist_S è la distanza dalla posizione scelta.

Ho letto sul metodo .stack ma non sono riuscito a capire come applicarlo per questo caso. Grazie per il tuo tempo!

NOTA: questo è solo un semplice esempio. I set di dati che sto cercando hanno un numero variabile di ubicazioni e numero di individui per posizione, quindi sono alla ricerca di una soluzione flessibile, se possibile

risposta

6

In realtà, i panda ha un comando wide_to_long che può comodamente fare ciò che si intende fare.

df = pd.DataFrame({'location' : ['A', 'A', 'A', 'B', 'B', 'B'], 
       'dist_to_A' : [0, 0, 0, 50, 50, 50], 
       'dist_to_B' : [50, 50, 50, 0, 0, 0], 
       'location_var': [10, 10, 10, 14, 14, 14], 
       'ind_var': [3, 8, 10, 1, 3, 4]}) 

df['ind'] = df.index 

#The `location` and `location_var` corresponds to the choices, 
#record them as dictionaries and drop them 
#(Just realized you had a cleaner way, copied from yous). 

ind_to_loc = dict(df['location']) 
loc_dict = dict(df.groupby('location').agg(lambda x : int(np.mean(x)))['location_var']) 
df.drop(['location_var', 'location'], axis = 1, inplace = True) 
# now reshape 
df_long = pd.wide_to_long(df, ['dist_to_'], i = 'ind', j = 'location') 

# use the dictionaries to get variables `choice` and `location_var` back. 

df_long['choice'] = df_long.index.map(lambda x: ind_to_loc[x[0]]) 
df_long['location_var'] = df_long.index.map(lambda x : loc_dict[x[1]]) 
print df_long.sort() 

Questo ti dà la tabella che hai chiesto:

   ind_var dist_to_ choice location_var 
ind location           
0 A    3   0  A   10 
    B    3  50  A   14 
1 A    8   0  A   10 
    B    8  50  A   14 
2 A    10   0  A   10 
    B    10  50  A   14 
3 A    1  50  B   10 
    B    1   0  B   14 
4 A    3  50  B   10 
    B    3   0  B   14 
5 A    4  50  B   10 
    B    4   0  B   14 

Naturalmente è possibile generare una variabile scelta che prende 0 e 1 se è quello che vuoi.

+0

Grazie Zhen Sun, questo sembra un approccio molto più pulito. Tuttavia, non corrisponde al mio problema. La variabile 'location' non ha errori. La variabile 'dist_to_' dovrebbe avere la distanza tra l'individuo (indicato dall'indice) e la posizione. La scelta indica ciò che l'individuo ha scelto in questa occasione (ha scelto la posizione A o B). Ho cercato di chiarirlo nella mia domanda, ma se non è ancora chiaro fammelo sapere e posso riscriverlo un po '. – cd98

+0

@ cd98, penso di aver capito la tua domanda. Sto dicendo nel tuo lungo tavolo, la variabile 'location' non sembra abbastanza corretta. In che modo 'ID = 0' ha' location' sia 'A' che' B'? 'ID = 0' si trova in' A' in base alla tabella larga. Inoltre, non capisco perché l'approccio non corrisponde al tuo problema. –

+0

ID identifica l'individuo. Ogni individuo sceglie tra la scelta A o B. I dati originali hanno solo i dati per la scelta che l'individuo prende. Il formato "lungo" che stavo cercando ha sia scelte per individuo che caratteristiche della scelta, incluse caratteristiche che dipendono solo dall'individuo (ind_var), solo dalla posizione (posizione var) o dall'individuo e dalla scelta (tale come posizione). Ogni ind. scegli solo una posizione. È un formato strano, ma è quello che richiede il mio programma di statistiche. Scusa se non era chiaro, spero che sia ora! Grazie per la tua disponibilità! – cd98

3

Sono un po 'curioso perché ti piacerebbe nel formato. C'è probabilmente un modo molto migliore per archiviare i tuoi dati. Ma qui va.

In [137]: import numpy as np 

In [138]: import pandas as pd 

In [139]: df_reshape_test = pd.DataFrame({'location' : ['A', 'A', 'A', 'B', 'B 
', 'B'], 'dist_to_A' : [0, 0, 0, 50, 50, 50], 'dist_to_B' : [50, 50, 50, 0, 0, 
0], 'location_var': [10, 10, 10, 14, 14, 14], 'ind_var': [3, 8, 10, 1, 3, 4]}) 

In [140]: print(df_reshape_test) 
    dist_to_A dist_to_B ind_var location location_var 
0   0   50  3  A   10 
1   0   50  8  A   10 
2   0   50  10  A   10 
3   50   0  1  B   14 
4   50   0  3  B   14 
5   50   0  4  B   14 

In [141]: # Get the new axis separately: 

In [142]: idx = pd.Index(df_reshape_test.index.tolist() * 2) 

In [143]: df2 = df_reshape_test[['ind_var', 'location', 'location_var']].reindex(idx) 

In [144]: print(df2) 
    ind_var location location_var 
0  3  A   10 
1  8  A   10 
2  10  A   10 
3  1  B   14 
4  3  B   14 
5  4  B   14 
0  3  A   10 
1  8  A   10 
2  10  A   10 
3  1  B   14 
4  3  B   14 
5  4  B   14 

In [145]: # Swap the location for the second half 

In [146]: # replace any 6 with len(df)/2 + 1 if you have more rows.d 

In [147]: df2['choice'] = [1] * 6 + [0] * 6 # may need to play with this. 

In [148]: df2.iloc[6:].location.replace({'A': 'B', 'B': 'A'}, inplace=True) 

In [149]: df2 = df2.sort() 

In [150]: df2['dist_S'] = np.abs((df2.choice - 1) * 50) 

In [151]: print(df2) 
    ind_var location location_var choice dist_S 
0  3  A   10  1  0 
0  3  B   10  0  50 
1  8  A   10  1  0 
1  8  B   10  0  50 
2  10  A   10  1  0 
2  10  B   10  0  50 
3  1  B   14  1  0 
3  1  A   14  0  50 
4  3  B   14  1  0 
4  3  A   14  0  50 
5  4  B   14  1  0 
5  4  A   14  0  50 

non sta andando bene generalizzare, ma ci sono probabilmente alternative (migliore) modi per aggirare le parti più brutti come la generazione del col scelta.

+0

Grazie per la risposta! Sono d'accordo che è un formato strano, ne ho solo bisogno perché il comando Stata [asclogit] (http://www.stata.com/help.cgi?asclogit) per logit condizionale (cioè caratteristiche variabili alternative) richiede un dataset con questa forma . Proverò la tua soluzione oggi e forse alcuni altri poster faranno il loro ingresso. – cd98

+0

Abbastanza giusto. Hai dato un'occhiata a [statsmodels] (http://statsmodels.sourceforge.net/devel/)? È un pacchetto python per l'inferenza econometrica/statistica. Non sono sicuro che qualcuno abbia implementato la logica condizionale, ma ha tutte le nozioni di base. – TomAugspurger

+0

Ho guardato [statsmodels] (http://statsmodels.sourceforge.net/devel/), ma finora hanno solo Logit Multinomiale (caratteristiche variabili individuali). Tuttavia, sembra che stiano lavorando su Conditional Logit in questo momento (si veda [questo blog] (http://gsocstatsmodels.blogspot.com/)) – cd98

2

Ok, questo ha richiesto più tempo, ma ecco una risposta più generale che funziona con un numero arbitrario di scelte per individuo. Sono sicuro che ci sono modi più semplici, quindi sarebbe bello se qualcuno potesse interpretare qualcosa di meglio per alcuni dei seguenti codici.

df = pd.DataFrame({'location' : ['A', 'A', 'A', 'B', 'B', 'B'], 'dist_to_A' : [0, 0, 0, 50, 50, 50], 'dist_to_B' : [50, 50, 50, 0, 0, 0], 'location_var': [10, 10, 10, 14, 14, 14], 'ind_var': [3, 8, 10, 1, 3, 4]}) 

che dà

dist_to_A dist_to_B ind_var location location_var 
0 0   50   3  A   10 
1 0   50   8  A   10 
2 0   50   10  A   10 
3 50   0   1  B   14 
4 50   0   3  B   14 
5 50   0   4  B   14 

Poi facciamo:

df.index.names = ['ind'] 

# Add choice var 

df['choice'] = 1 

# Create dictionaries we'll use later 

ind_to_loc = dict(df['location']) 
# gives ind_to_loc equal to {0 : 'A', 1 : 'A', 2 : 'A', 3 : 'B', 4 : 'B', 5: 'B'} 

ind_dict = dict(df['ind_var']) 
#gives { 0: 3, 1 : 8, 2 : 10, 3: 1, 4 : 3, 5: 4} 

loc_dict = dict( df.groupby('location').agg(lambda x : int(np.mean(x)))['location_var'] ) 
# gives {'A' : 10, 'B' : 14} 

Ora creo un Multi-Index e fare un re-index per ottenere una forma allungata

df = df.set_index([df.index, df['location']]) 

df.index.names = ['ind', 'location'] 

# re-index to long shape 

loc_list = ['A', 'B'] 
ind_list = [0, 1, 2, 3, 4, 5] 
new_shape = [ (ind, loc) for ind in ind_list for loc in loc_list] 
idx = pd.Index(new_shape) 
df_long = df.reindex(idx, method = None) 
df_long.index.names = ['ind', 'loc'] 

La forma lunga è simile a questa:

  dist_to_A dist_to_B ind_var location location_var choice 
ind loc                
0 A   0   50  3  A   10  1 
    B   NaN  NaN  NaN  NaN   NaN  NaN 
1 A   0   50  8  A   10  1 
    B   NaN  NaN  NaN  NaN   NaN  NaN 
2 A   0   50  10  A   10  1 
    B   NaN  NaN  NaN  NaN   NaN  NaN 
3 A   NaN  NaN  NaN  NaN   NaN  NaN 
    B   50   0  1  B   14  1 
4 A   NaN  NaN  NaN  NaN   NaN  NaN 
    B   50   0  3  B   14  1 
5 A   NaN  NaN  NaN  NaN   NaN  NaN 
    B   50   0  4  B   14  1 

Così ora riempire i valori della NaN con i dizionari:

df_long['ind_var'] = df_long.index.map(lambda x : ind_dict[x[0]]) 
df_long['location'] = df_long.index.map(lambda x : ind_to_loc[x[0]]) 
df_long['location_var'] = df_long.index.map(lambda x : loc_dict[x[1]]) 

# Fill in choice 
df_long['choice'] = df_long['choice'].fillna(0) 

Infine, tutto ciò che resta è la creazione di dist_S
io barare qui e assumere posso creare un dizionario nidificato come questo uno

nested_loc = {'A' : {'A' : 0, 'B' : 50}, 'B' : {'A' : 50, 'B' : 0}} 

(Questo si legge: se siete in posizione a, quindi posizione a è a 0 km e il percorso B a 50 km)

def nested_f(x):  
    return nested_loc[x[0]][x[1]] 

df_long = df_long.reset_index() 
df_long['dist_S'] = df_long[['loc', 'location']].apply(nested_f, axis=1) 

df_long = df_long.drop(['dist_to_A', 'dist_to_B', 'location'], axis = 1) 

df_long 

dà il risultato desiderato

ind loc ind_var location_var choice dist_S 
0 0 A 3   10   1  0 
1 0 B 3   14   0  50 
2 1 A 8   10   1  0 
3 1 B 8   14   0  50 
4 2 A 10  10   1  0 
5 2 B 10  14   0  50 
6 3 A 1   10   0  50 
7 3 B 1   14   1  0 
8 4 A 3   10   0  50 
9 4 B 3   14   1  0 
10 5 A 4   10   0  50 
11 5 B 4   14   1  0