[PYTHON] À propos de MultiIndex of Pandas

Cet article est l'article du 19e jour du Calendrier de l'Avent Python Partie 2 2015.

J'ai essayé de m'inscrire au Calendrier de l'Avent, mais récemment je n'ai pas écrit un tel Python et même si je l'écris, je ne peux pas l'écrire parce que j'ai fait trop de choses spéciales dans les affaires, donc ça me rappelle un peu maintenant, mais c'est une petite histoire de pandas. J'écrirai sur les pandas, qui sont familiers dans le prétraitement et l'agrégation des données, et sur Multiindex, que je connais mais est un peu difficile à comprendre.

Environnement au moment de la rédaction

Le code qui apparaît ci-dessous est

import pandas as pd

Il est écrit sur le principe que c'est fait. De plus, la table collée est une copie de la version to_html, elle est donc légèrement différente de l'affichage sur le notebook jupyter.

Qu'est-ce que MultiIndex

MultiIndex / Advanced Indexing Une fonction pour indexer plusieurs colonnes avec DataFrame de pandas. Ceci est utile lorsque plusieurs valeurs sont utilisées comme clés pour identifier de manière unique les données.

Préparation des données et examen des index ordinaires

Les index ordinaires sont appelés dans cet article Index unique pour plus de commodité, contrairement à Multi Index. (Il n'y a pas de tel type)

Préparation des données

Préparez le csv suivant pour l'explication

sample.csv


name,year,product,expected,actual
Taro,2013,A,116,119
Taro,2013,B,131,149
Taro,2014,A,151,124
Taro,2014,B,125,107
Taro,2015,A,135,109
Taro,2015,B,142,148
Hanako,2013,A,170,130
Hanako,2013,B,113,190
Hanako,2014,A,102,142
Hanako,2014,B,183,125
Hanako,2015,A,169,120
Hanako,2015,B,134,199

Lisez ceci avec les pandas.

df1 = pd.read_csv('sample.csv')
name year product expected actual
0 Taro 2013 A 116 119
1 Taro 2013 B 131 149
2 Taro 2014 A 151 124
3 Taro 2014 B 125 107
4 Taro 2015 A 135 109
5 Taro 2015 B 142 148
6 Hanako 2013 A 170 130
7 Hanako 2013 B 113 190
8 Hanako 2014 A 102 142
9 Hanako 2014 B 183 125
10 Hanako 2015 A 169 120
11 Hanako 2015 B 134 199

Les étiquettes de ligne de cette table, «0,1,2 ...», sont «data.index», et les étiquettes de colonne »,« nom »,« année », ...« sont »des colonnes de données». A également un type de données de pandas.Index.

Parce que pandas.Index a un membre appelé nom

df1.index.name = "id"
df1.columns.name = "header"

Puis

header name year product expected actual
id
0 Taro 2013 A 116 119
1 Taro 2013 B 131 149
2 Taro 2014 A 151 124
3 Taro 2014 B 125 107
4 Taro 2015 A 135 109
5 Taro 2015 B 142 148
6 Hanako 2013 A 170 130
7 Hanako 2013 B 113 190
8 Hanako 2014 A 102 142
9 Hanako 2014 B 183 125
10 Hanako 2015 A 169 120
11 Hanako 2015 B 134 199
Ce sera une telle table.

Sélection des données

df1["name"]

production


id
0       Taro
1       Taro
2       Taro
3       Taro
4       Taro
5       Taro
6     Hanako
7     Hanako
8     Hanako
9     Hanako
10    Hanako
11    Hanako
Name: name, dtype: object
df1.loc[3]

production


header
name        Taro
year        2014
product        B
expected     125
actual       107
Name: 3, dtype: object
df1.iloc[3]

Cet index de temps est un index de ligne, donc la sortie est la même.

df1.ix[3:5,"product":"actual"]

production

product expected actual
3 B 125 107
4 A 135 109
5 B 142 148
df1[(df1["name"] == "Hanako")&(df1["product"] == "A")]

production

header name year product expected actual
id
6 Hanako 2013 A 170 130
8 Hanako 2014 A 102 142
10 Hanako 2015 A 169 120

Voir d'autres articles et livres pour plus de détails.

Paramètres MultiIndex

Le sujet principal est d'ici. Comme vous pouvez le voir, les données que vous venez de lire

Dans un tel cas, utilisez MultiIndex pour organiser proprement les données.

df2 = pd.read_csv("sample.csv",index_col=["name","year","product"])
expected actual
name year product
Taro 2013 A 116 119
B 131 149
2014 A 151 124
B 125 107
2015 A 135 109
B 142 148
Hanako 2013 A 170 130
B 113 190
2014 A 102 142
B 183 125
2015 A 169 120
B 134 199

Après lecture des données ou lors de l'application de MultiIndex au DataFrame créé par divers traitements PostScript 2016/3/18 </ font> Si vous utilisez la fonction set_index, la colonne spécifiée sera indexée. (Je ne le savais pas car il n'était pas répertorié sur la page MultiIndex du document officiel ...)

df2 = df1.set_index(["name","year","product"], drop=True)

Si drop = True, la colonne indexée sera supprimée. Au retour

df1 = df2.reset_index()

À Fin de l'ajout </ font>

pd.MultiIndex.from_arrays()
pd.MultiIndex.from_product()
pd.MultiIndex.from_tuples()

Si vous utilisez autour, ce sera gérable. Au fait, pd.MultiIndex.from_product crée un index pour les boucles imbriquées lors du passage de plusieurs collections (comme itertools.product). Par exemple, pour créer le même index que «df2»

pd.MultiIndex.from_product((["Taro","Hanako"],[2013,2014,2015],["A","B"]),\
    names=["name","year","product"])

Tu peux le faire.

Sélection des données

Lors de la sélection d'une ligne, passez la touche d'index.

df2.loc[("Taro",2013,"A")]

production


expected    116
actual      119
Name: (Taro, 2013, A), dtype: int64

Si vous passez un taple à mi-chemin, le tableau sera retourné, mais comme PerformanceWarning sera émis pour la spécification jusqu'au niveau à mi-chemin, il est préférable de ne pas l'utiliser sauf lorsque vous souhaitez regarder temporairement à l'intérieur. Il n'y a aucun problème si vous spécifiez le premier niveau (nom dans ce cas) ou tous les niveaux.

df2.loc[("Taro",2013)]

Sortie (PerformanceWarning)

expected actual
product
A 116 119
B 131 149

Utilisez xs pour spécifier jusqu'au niveau intermédiaire ou uniquement au milieu

df2.xs(["Taro","A"],level=[0,2])

production

expected actual
year
2013 116 119
2014 151 124
2015 135 109

L'avertissement n'est plus affiché, mais même si vous écrivez le même processus que ci-dessus, celui-ci est un peu plus lent ...

Utilisation de MultiIndex

Puisque pandas.Index n'est pas pandas.Series, il ne peut pas être utilisé comme une ligne normale, et il est sobre et stressant. Ensuite, je voudrais dire qu'il n'y a pas de mal à conserver Single Index et Series, mais comme il y a beaucoup d'efforts, réfléchissez à où les utiliser.

Rechercher des données déterminées de manière unique en utilisant plusieurs colonnes comme clés

Comme je l'ai écrit plus tôt, c'est probablement l'utilisation principale.

df2.loc[("Taro",2013,"A")]

Si vous essayez de faire de même avec Single Index,

df1[(df1["name"] == "Taro")&(df1["year"] == 2013)&(df1["product"] == "A")].iloc[0]

On a l'impression que c'est sale (il y a peut-être une meilleure façon de l'écrire). Bien sûr, il y a aussi une différence de vitesse. Lorsque j'ai essayé d'utiliser environ 50000 données, j'ai constaté qu'il n'y avait qu'une différence de 2 à 3 fois dans un essai. J'ai essayé de vérifier avec %% timeit, mais `` df2` semble être mis en cache et je n'ai pas pu comparer.

De plus, si vous n'êtes pas sûr qu'il existe des données correspondant à la clé spécifiée, MultiIndex

("Taro",2013,"A") in df2.index

Mais avec un seul index

df1[(df1["name"] == "Taro")&(df1["year"] == 2013)&(df1["product"] == "A")].shape[0]>0

Je dois le faire (il y a peut-être une meilleure façon de l'écrire)

Pour l'affichage

Étant donné que la sortie de MultiIndex avec des index de clés imbriqués est très visible pour les humains, il est possible d'utiliser MultiIndex uniquement pour la sortie. DataFrame peut produire dans de nombreux formats tels que html, excel, latex, etc., et même s'il s'agit d'Excel, il combinera correctement les cellules selon MultiIndex, donc c'est pratique. Au fait, avec df.to_csv, même si c'est MultiIndex, il affichera toutes les lignes correctement.

Autres méthodes de fonctionnement, etc.

  • Utilisez df.index.get_level_values pour récupérer un niveau d'index
  • Utilisez df.reset_index () pour renvoyer MultiIndex à SingleIndex. Une colonne pour chaque niveau est ajoutée pour créer un DataFrame dont le numéro de série est index.
  • En plus, il y a des tranches etc., mais je ne sais pas comment m'en servir, je vais donc en profiter une autre

Recommended Posts