J'ai un bloc de données avec un index hiérarchique dans l'axe 1 (colonnes) (à partir d'une groupby.agg
opération):
USAF WBAN year month day s_PC s_CL s_CD s_CNT tempf
sum sum sum sum amax amin
0 702730 26451 1993 1 1 1 0 12 13 30.92 24.98
1 702730 26451 1993 1 2 0 0 13 13 32.00 24.98
2 702730 26451 1993 1 3 1 10 2 13 23.00 6.98
3 702730 26451 1993 1 4 1 0 12 13 10.04 3.92
4 702730 26451 1993 1 5 3 0 10 13 19.94 10.94
Je veux l'aplatir, pour qu'il ressemble à ceci (les noms ne sont pas critiques - je pourrais renommer):
USAF WBAN year month day s_PC s_CL s_CD s_CNT tempf_amax tmpf_amin
0 702730 26451 1993 1 1 1 0 12 13 30.92 24.98
1 702730 26451 1993 1 2 0 0 13 13 32.00 24.98
2 702730 26451 1993 1 3 1 10 2 13 23.00 6.98
3 702730 26451 1993 1 4 1 0 12 13 10.04 3.92
4 702730 26451 1993 1 5 3 0 10 13 19.94 10.94
Comment puis-je faire cela? (J'ai beaucoup essayé, en vain.)
Selon une suggestion, voici la tête sous forme de dict
{('USAF', ''): {0: '702730',
1: '702730',
2: '702730',
3: '702730',
4: '702730'},
('WBAN', ''): {0: '26451', 1: '26451', 2: '26451', 3: '26451', 4: '26451'},
('day', ''): {0: 1, 1: 2, 2: 3, 3: 4, 4: 5},
('month', ''): {0: 1, 1: 1, 2: 1, 3: 1, 4: 1},
('s_CD', 'sum'): {0: 12.0, 1: 13.0, 2: 2.0, 3: 12.0, 4: 10.0},
('s_CL', 'sum'): {0: 0.0, 1: 0.0, 2: 10.0, 3: 0.0, 4: 0.0},
('s_CNT', 'sum'): {0: 13.0, 1: 13.0, 2: 13.0, 3: 13.0, 4: 13.0},
('s_PC', 'sum'): {0: 1.0, 1: 0.0, 2: 1.0, 3: 1.0, 4: 3.0},
('tempf', 'amax'): {0: 30.920000000000002,
1: 32.0,
2: 23.0,
3: 10.039999999999999,
4: 19.939999999999998},
('tempf', 'amin'): {0: 24.98,
1: 24.98,
2: 6.9799999999999969,
3: 3.9199999999999982,
4: 10.940000000000001},
('year', ''): {0: 1993, 1: 1993, 2: 1993, 3: 1993, 4: 1993}}
df[:5].to_dict()
comme exemple pour que d'autres puissent la lire dans votre jeu de données?pandas
outil de suivi des problèmes pour implémenter une méthode dédiée à cet effet.dat.columns = dat.columns.to_flat_index()
. Fonction pandas intégrée.Réponses:
Je pense que la façon la plus simple de le faire serait de définir les colonnes au niveau supérieur:
Remarque: si le niveau to a un nom, vous pouvez également y accéder par ce biais, plutôt que par 0.
.
Si vous souhaitez combiner /
join
votre MultiIndex en un seul index (en supposant que vous n'avez que des entrées de chaîne dans vos colonnes), vous pouvez:Remarque: nous devons
strip
laisser un espace pour quand il n'y a pas de second index.la source
['_'.join(col).rstrip('_') for col in df.columns.values]
sum s_CD
place des_CD sum
, on peut le fairedf.columns = ['_'.join(col).rstrip('_') for col in [c[::-1] for c in df.columns.values]]
.la source
pd.DataFrame(df.to_records(), columns=df.index.names + list(df.columns))
pd.DataFrame(df_volume.to_records(), index=df_volume.index).drop('index', axis=1)
Toutes les réponses actuelles sur ce sujet doivent avoir été un peu datées. Depuis la
pandas
version 0.24.0, le.to_flat_index()
fait ce dont vous avez besoin.De la propre documentation de panda :
Un exemple simple de sa documentation:
Appliquer
to_flat_index()
:L'utiliser pour remplacer l'existant
pandas
colonneUn exemple de la façon dont vous l'utiliseriez
dat
, qui est un DataFrame avec uneMultiIndex
colonne:la source
La réponse d'Andy Hayden est certainement le moyen le plus simple - si vous voulez éviter les étiquettes de colonnes en double, vous devez modifier un peu
la source
la source
Et si vous souhaitez conserver les informations d'agrégation du deuxième niveau du multiindex, vous pouvez essayer ceci:
la source
new_cols
n'est pas défini.La façon la plus pythonique de le faire pour utiliser la
map
fonction.Sortie
print(df.columns)
:Mise à jour à l'aide de Python 3.6+ avec chaîne f:
Production:
la source
La solution la plus simple et la plus intuitive pour moi était de combiner les noms de colonnes à l'aide de get_level_values . Cela empêche les noms de colonne en double lorsque vous effectuez plusieurs agrégations sur la même colonne:
Si vous voulez un séparateur entre les colonnes, vous pouvez le faire. Cela renverra la même chose que le commentaire de Seiji Armstrong sur la réponse acceptée qui ne comprend que des traits de soulignement pour les colonnes avec des valeurs dans les deux niveaux d'index:
Je sais que cela fait la même chose que la grande réponse d'Andy Hayden ci-dessus, mais je pense que c'est un peu plus intuitif de cette façon et est plus facile à retenir (donc je n'ai pas à continuer de faire référence à ce fil), en particulier pour les utilisateurs novices de pandas .
Cette méthode est également plus extensible dans le cas où vous pouvez avoir 3 niveaux de colonne.
la source
Après avoir lu toutes les réponses, j'ai trouvé ceci:
Usage:
Étant donné une trame de données:
Méthode d'agrégation unique : variables résultantes nommées de la même manière que source :
df.groupby(by="grouper",
as_index = False)
ou.agg(...)
.reset_index ()Variable source unique, agrégations multiples : variables résultantes nommées d'après les statistiques :
a = df.groupby(..).agg(..); a.columns = a.columns.droplevel(0); a.reset_index()
.Variables multiples, agrégations multiples : variables résultantes nommées (varname) _ (statname) :
a.columns = ["_".join(filter(None, map(str, levels))) for levels in a.columns.values]
sous le capot (puisque cette forme deagg()
résultats enMultiIndex
les colonnes).my_flatten_cols
aide, il pourrait être plus facile de taper la solution suggérée par @Seigi :a.columns = ["_".join(t).rstrip("_") for t in a.columns.values]
qui fonctionne de façon similaire dans ce cas (mais échoue si vous avez des étiquettes numériques sur des colonnes)a.columns = ["_".join(tuple(map(str, t))).rstrip("_") for t in a.columns.values]
), mais je ne comprends pas pourquoi l'tuple()
appel est nécessaire, et je croisrstrip()
que ce n'est nécessaire que si certaines colonnes ont un descripteur comme("colname", "")
( ce qui peut arriver si vousreset_index()
avant d'essayer de réparer.columns
)Vous souhaitez nommer les variables obtenues manuellement: (ce qui est dépréciée depuis pandas géants 0.20.0 avec aucune alternative adéquate à partir de 0,23 )
res.columns = ['A_sum', 'B_sum', 'count']
ou.join()
ing plusieursgroupby
instructions.Cas traités par la fonction d'assistance
map(str, ..)
filter(None, ..)
columns.values
retourne les noms (str
et non les tuples).agg()
vous devrez peut-être conserver l'étiquette la plus basse d'une colonne ou concaténer plusieurs étiquettesreset_index()
pouvoir travailler avec les colonnes de regroupement de manière régulière, donc il le fait par défautla source
tuple()
vous en avez besoin, vous voudrez peut-être commenter le message de jxstanford. Dans le cas contraire, il pourrait être utile d'inspecter le.columns.values
dans l'exemple fourni:[('val1', 'min'), (2, 'sum'), (2, 'size')]
. 1)for t in a.columns.values
boucles sur les colonnes, pour la deuxième colonnet == (2, 'sum')
; 2)map(str, t)
s'appliquestr()
à chaque "niveau", résultant en('2', 'sum')
; 3)"_".join(('2','sum'))
résulte en "2_sum",Une solution générale qui gère plusieurs niveaux et types mixtes:
la source
df.columns = ['_'.join(tuple(map(str, t))).rstrip('_') for t in df.columns.values]
Peut-être un peu en retard, mais si vous n'êtes pas inquiet des noms de colonnes en double:
la source
(year, )
(tempf, amax)
Si vous voulez avoir un séparateur dans le nom entre les niveaux, cette fonction fonctionne bien.
la source
df.columns = ["_".join(filter(None, c)) for c in df.columns]
Après @jxstanford et @ tvt173, j'ai écrit une fonction rapide qui devrait faire l'affaire, quels que soient les noms de colonne chaîne / int:
la source
Vous pouvez également faire comme ci-dessous. Considérez
df
être votre dataframe et supposez un index à deux niveaux (comme c'est le cas dans votre exemple)la source
Je vais partager une méthode simple qui a fonctionné pour moi.
la source
Pour aplatir un MultiIndex à l'intérieur d'une chaîne d'autres méthodes DataFrame, définissez une fonction comme celle-ci:
Utilisez ensuite la
pipe
méthode pour appliquer cette fonction dans la chaîne de méthodes DataFrame, aprèsgroupby
etagg
mais avant toute autre méthode de la chaîne:la source
Une autre routine simple.
la source