Convertir la ligne en en-tête de colonne pour Pandas DataFrame,


111

Les données avec lesquelles je dois travailler sont un peu désordonnées. Il a des noms d'en-tête à l'intérieur de ses données. Comment puis-je choisir une ligne dans un dataframe pandas existant et en faire (la renommer en) un en-tête de colonne?

Je veux faire quelque chose comme:

header = df[df['old_header_name1'] == 'new_header_name1']

df.columns = header

Réponses:


196
In [21]: df = pd.DataFrame([(1,2,3), ('foo','bar','baz'), (4,5,6)])

In [22]: df
Out[22]: 
     0    1    2
0    1    2    3
1  foo  bar  baz
2    4    5    6

Définissez les étiquettes de colonne pour qu'elles correspondent aux valeurs de la deuxième ligne (emplacement d'index 1):

In [23]: df.columns = df.iloc[1]

Si l'index a des libellés uniques, vous pouvez supprimer la deuxième ligne en utilisant:

In [24]: df.drop(df.index[1])
Out[24]: 
1 foo bar baz
0   1   2   3
2   4   5   6

Si l'index n'est pas unique, vous pouvez utiliser:

In [133]: df.iloc[pd.RangeIndex(len(df)).drop(1)]
Out[133]: 
1 foo bar baz
0   1   2   3
2   4   5   6

L'utilisation df.drop(df.index[1])supprime toutes les lignes avec le même libellé que la deuxième ligne. Parce que les index non uniques peuvent conduire à des pierres d'achoppement (ou des bogues potentiels) comme celui-ci, il est souvent préférable de veiller à ce que l'index soit unique (même si Pandas n'en a pas besoin).


Merci beaucoup pour votre réponse rapide! Comment puis-je choisir une ligne par valeur au lieu de l'emplacement de l'index pour en faire un en-tête? Donc, pour votre exemple, quelque chose comme .. df.columns = df [df [0] == 'foo']
EK

Le problème avec cela est qu'il pourrait y avoir plus d'une ligne qui a la valeur "foo". Une façon de contourner ce problème est de choisir explicitement la première telle ligne: df.columns = df.iloc[np.where(df[0] == 'foo')[0][0]].
unutbu

Ah je vois pourquoi tu as fait ça. Pour mon cas, je sais qu'il n'y a qu'une seule ligne qui a la valeur "foo". Alors ça va. Je viens de faire de cette façon, je suppose que c'est le même que celui que vous m'avez donné ci-dessus. idx_loc = df [df [0] == 'toto']. index.tolist () [0] df.columns = df.iloc [idx_loc]
EK

63

Cela fonctionne (pandas v'0.19.2 '):

df.rename(columns=df.iloc[0])

22
Vous pouvez supprimer la ligne "en-tête" en ajoutant.drop(df.index[0])
ostrokach

J'aime mieux cela que la réponse acceptée. J'adore les solutions courtes en ligne.
Javier

13

Il serait plus facile de recréer la trame de données. Cela interpréterait également les types de colonnes à partir de zéro.

headers = df.iloc[0]
new_df  = pd.DataFrame(df.values[1:], columns=headers)

4

Vous pouvez spécifier l'index de ligne dans les constructeurs read_csv ou read_html via le headerparamètre qui représente Row number(s) to use as the column names, and the start of the data. Cela a l'avantage de supprimer automatiquement toutes les lignes précédentes qui sont supposées être indésirables.

import pandas as pd
from io import StringIO

In[1]
    csv = '''junk1, junk2, junk3, junk4, junk5
    junk1, junk2, junk3, junk4, junk5
    pears, apples, lemons, plums, other
    40, 50, 61, 72, 85
    '''

    df = pd.read_csv(StringIO(csv), header=2)
    print(df)

Out[1]
       pears   apples   lemons   plums   other
    0     40       50       61      72      85
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.