les pandas convertissent certaines colonnes en lignes

117

Mon ensemble de données contient donc des informations par emplacement pour n dates. Le problème est que chaque date est en fait un en-tête de colonne différent. Par exemple, le CSV ressemble à

location    name    Jan-2010    Feb-2010    March-2010
A           "test"  12          20          30
B           "foo"   18          20          25

Ce que je voudrais, c'est que ça ressemble

location    name    Date        Value
A           "test"  Jan-2010    12       
A           "test"  Feb-2010    20
A           "test"  March-2010  30
B           "foo"   Jan-2010    18       
B           "foo"   Feb-2010    20
B           "foo"   March-2010  25

le problème est que je ne sais pas combien de dates il y a dans la colonne (même si je sais qu'elles commenceront toujours après le nom)

Wizuriel
la source

Réponses:

209

MISE
À JOUR Depuis la v0.20, meltest une fonction de premier ordre, vous pouvez maintenant utiliser

df.melt(id_vars=["location", "name"], 
        var_name="Date", 
        value_name="Value")

  location    name        Date  Value
0        A  "test"    Jan-2010     12
1        B   "foo"    Jan-2010     18
2        A  "test"    Feb-2010     20
3        B   "foo"    Feb-2010     20
4        A  "test"  March-2010     30
5        B   "foo"  March-2010     25

ANCIENNES VERSIONS (ER): <0,20

Vous pouvez utiliser pd.meltpour obtenir la plupart du chemin, puis trier:

>>> df
  location  name  Jan-2010  Feb-2010  March-2010
0        A  test        12        20          30
1        B   foo        18        20          25
>>> df2 = pd.melt(df, id_vars=["location", "name"], 
                  var_name="Date", value_name="Value")
>>> df2
  location  name        Date  Value
0        A  test    Jan-2010     12
1        B   foo    Jan-2010     18
2        A  test    Feb-2010     20
3        B   foo    Feb-2010     20
4        A  test  March-2010     30
5        B   foo  March-2010     25
>>> df2 = df2.sort(["location", "name"])
>>> df2
  location  name        Date  Value
0        A  test    Jan-2010     12
2        A  test    Feb-2010     20
4        A  test  March-2010     30
1        B   foo    Jan-2010     18
3        B   foo    Feb-2010     20
5        B   foo  March-2010     25

(Vous voudrez peut-être ajouter un .reset_index(drop=True), juste pour garder la sortie propre.)

Remarque : pd.DataFrame.sort a été abandonné au profit de pd.DataFrame.sort_values.

DSM
la source
@DSM quel serait l'inverse de cette fonction. c'est-à-dire comment convertir df2[retour] endf
3kstc
1
@ 3kstc Essayez ici ou ici . Vous souhaitez vous pencher sur les pivots. Peut-être pandas.pivot_table(df2,values='Value',index=['location','name'],columns='Date').reset_index().
Teepeemm
1
@DSM y a-t-il un moyen de revenir en arrière? Cela signifie que j'ai beaucoup de lignes avec le même nom et que je voudrais que toutes les dates soient sur des colonnes différentes
Adrian
17

Utiliser set_indexavec stackfor MultiIndex Series, puis pour DataFrameajouter reset_indexavec rename:

df1 = (df.set_index(["location", "name"])
         .stack()
         .reset_index(name='Value')
         .rename(columns={'level_2':'Date'}))
print (df1)
  location  name        Date  Value
0        A  test    Jan-2010     12
1        A  test    Feb-2010     20
2        A  test  March-2010     30
3        B   foo    Jan-2010     18
4        B   foo    Feb-2010     20
5        B   foo  March-2010     25
jezrael
la source
5

Je suppose que j'ai trouvé une solution plus simple

temp1 = pd.melt(df1, id_vars=["location"], var_name='Date', value_name='Value')
temp2 = pd.melt(df1, id_vars=["name"], var_name='Date', value_name='Value')

Concater le tout temp1avec temp2la colonne dename

temp1['new_column'] = temp2['name']

Vous avez maintenant ce que vous avez demandé.

Prométhée
la source
4

pd.wide_to_long

Vous pouvez ajouter un préfixe à vos colonnes d'année, puis alimenter directement vers pd.wide_to_long. Je ne prétendrai pas que c'est efficace , mais cela peut dans certaines situations être plus pratique que pd.melt, par exemple lorsque vos colonnes ont déjà un préfixe approprié.

df.columns = np.hstack((df.columns[:2], df.columns[2:].map(lambda x: f'Value{x}')))

res = pd.wide_to_long(df, stubnames=['Value'], i='name', j='Date').reset_index()\
        .sort_values(['location', 'name'])

print(res)

   name        Date location  Value
0  test    Jan-2010        A     12
2  test    Feb-2010        A     20
4  test  March-2010        A     30
1   foo    Jan-2010        B     18
3   foo    Feb-2010        B     20
5   foo  March-2010        B     25
jpp
la source