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)


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 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

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é.


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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.