そのため、サブサンプリング/断面を行うためのMultiIndexがなくてもDataFrame.groupbyを使用できることを学びました。
一方、DataFrameにMultiIndexがある場合でも、DataFrame.groupbyを使用してサブサンプリング/断面を実行する必要があります。
では、印刷時に階層が非常に便利できれいに表示されることを除けば、MultiIndexは何に適しているのでしょうか。
そのため、サブサンプリング/断面を行うためのMultiIndexがなくてもDataFrame.groupbyを使用できることを学びました。
一方、DataFrameにMultiIndexがある場合でも、DataFrame.groupbyを使用してサブサンプリング/断面を実行する必要があります。
では、印刷時に階層が非常に便利できれいに表示されることを除けば、MultiIndexは何に適しているのでしょうか。
階層インデックス(「マルチレベル」インデックスとも呼ばれます)は、pandas0.4リリースで導入されました。
これにより、特に高次元のデータを操作するための、非常に高度なデータ分析と操作への扉が開かれます。本質的には、たとえば、任意の高次元データを2次元の表形式構造(DataFrame)に効果的に格納および操作できます。
次のようにデータフレームを構築することを想像してみてくださいMultiIndex
:-
import pandas as pd
import numpy as np
np.arrays = [['one','one','one','two','two','two'],[1,2,3,1,2,3]]
df = pd.DataFrame(np.random.randn(6,2),index=pd.MultiIndex.from_tuples(list(zip(*np.arrays))),columns=['A','B'])
df # This is the dataframe we have generated
A B
one 1 -0.732470 -0.313871
2 -0.031109 -2.068794
3 1.520652 0.471764
two 1 -0.101713 -1.204458
2 0.958008 -0.455419
3 -0.191702 -0.915983
これdf
は単に2次元のデータ構造です
df.ndim
2
しかし、出力を見ると、3次元のデータ構造として想像することができます。
one
1
データ付き-0.732470 -0.313871
。one
2
データ付き-0.031109 -2.068794
。one
3
データ付き1.520652 0.471764
。別名:「2次元の表形式の構造で任意の高次元データを効果的に保存および操作する」
これは単なる「きれいなディスプレイ」ではありません。階層インデックスが作成されたため、データを簡単に取得できるという利点があります。
例えば。
In [44]: df.ix["one"]
Out[44]:
A B
1 -0.732470 -0.313871
2 -0.031109 -2.068794
3 1.520652 0.471764
「1つ」に属するデータのグループに対してのみ新しいデータフレームを提供します。
そして、これを行うことで、データ選択をさらに絞り込むことができます:-
In [45]: df.ix["one"].ix[1]
Out[45]:
A -0.732470
B -0.313871
Name: 1
そしてもちろん、特定の値が必要な場合は、次の例を示します。-
In [46]: df.ix["one"].ix[1]["A"]
Out[46]: -0.73247029752040727
したがって、さらに多くのインデックスがある場合(上記の例に示されている2つのインデックス以外)、基本的に、を必要とせずに、本当に関心のあるデータセットをドリルダウンして選択できますgroupby
。
データフレームから断面(行または列)を取得することもできます...
行別:-
In [47]: df.xs('one')
Out[47]:
A B
1 -0.732470 -0.313871
2 -0.031109 -2.068794
3 1.520652 0.471764
列別:-
In [48]: df.xs('B', axis=1)
Out[48]:
one 1 -0.313871
2 -2.068794
3 0.471764
two 1 -1.204458
2 -0.455419
3 -0.915983
Name: B
@Calvin Chengによる素晴らしい投稿ですが、私もこれを突き刺すと思いました。
MultiIndexを使用する場合:
なぜ(あなたの中心的な質問)-少なくともこれらはIMOの最大の利点です:
例:
Dollars Units
Date Store Category Subcategory UPC EAN
2018-07-10 Store 1 Alcohol Liqour 80480280024 154.77 7
Store 2 Alcohol Liqour 80480280024 82.08 4
Store 3 Alcohol Liqour 80480280024 259.38 9
Store 1 Alcohol Liquor 80432400630 477.68 14
674545000001 139.68 4
Store 2 Alcohol Liquor 80432400630 203.88 6
674545000001 377.13 13
Store 3 Alcohol Liquor 80432400630 239.19 7
674545000001 432.32 14
Store 1 Beer Ales 94922755711 65.17 7
702770082018 174.44 14
736920111112 50.70 5
Store 2 Beer Ales 94922755711 129.60 12
702770082018 107.40 10
736920111112 59.65 5
Store 3 Beer Ales 94922755711 154.00 14
702770082018 137.40 10
736920111112 107.88 12
Store 1 Beer Lagers 702770081011 156.24 12
Store 2 Beer Lagers 702770081011 137.06 11
Store 3 Beer Lagers 702770081011 119.52 8
1)店舗間の売上を簡単に比較したい場合は、df.unstack('Store')
すべてを並べて並べることができます。
Dollars Units
Store Store 1 Store 2 Store 3 Store 1 Store 2 Store 3
Date Category Subcategory UPC EAN
2018-07-10 Alcohol Liqour 80480280024 154.77 82.08 259.38 7 4 9
Liquor 80432400630 477.68 203.88 239.19 14 6 7
674545000001 139.68 377.13 432.32 4 13 14
Beer Ales 94922755711 65.17 129.60 154.00 7 12 14
702770082018 174.44 107.40 137.40 14 10 10
736920111112 50.70 59.65 107.88 5 5 12
Lagers 702770081011 156.24 137.06 119.52 12 11 8
2)複数の列で簡単に計算することもできます。たとえば、df['Dollars'] / df['Units']
複数の操作を行わないすべてのストアについて、各ストアのドルをその単位で除算します。
Store Store 1 Store 2 Store 3
Date Category Subcategory UPC EAN
2018-07-10 Alcohol Liqour 80480280024 22.11 20.52 28.82
Liquor 80432400630 34.12 33.98 34.17
674545000001 34.92 29.01 30.88
Beer Ales 94922755711 9.31 10.80 11.00
702770082018 12.46 10.74 13.74
736920111112 10.14 11.93 8.99
Lagers 702770081011 13.02 12.46 14.94
3)次に、を使用する代わりに、特定の行だけにフィルタリングする場合
df[(df[col1] == val1) and (df[col2] == val2) and (df[col3] == val3)]
形式では、代わりに.xsまたは.queryを使用できます(はい、これらは通常のdfsで機能しますが、あまり役に立ちません)。代わりに、構文は次のようになります。
df.xs((val1, val2, val3), level=(col1, col2, col3))
私がまとめたこのチュートリアルノートブックには、さらに多くの例があります。
マルチインデックスを使用する代わりに、データフレームの複数の列を使用してデータを保存することもできます。マルチインデックスは、ナイーブな列ストレージよりもパフォーマンスが向上すると予想されますが、Pandas v 1.1.4の時点では、そうではないようです。
import numpy as np
import pandas as pd
np.random.seed(2020)
inv = pd.DataFrame({
'store_id': np.random.choice(10000, size=10**7),
'product_id': np.random.choice(1000, size=10**7),
'stock': np.random.choice(100, size=10**7),
})
# Create a DataFrame with a multiindex
inv_multi = inv.groupby(['store_id', 'product_id'])[['stock']].agg('sum')
print(inv_multi)
stock
store_id product_id
0 2 48
4 18
5 58
7 149
8 158
... ...
9999 992 132
995 121
996 105
998 99
999 16
[6321869 rows x 1 columns]
# Create a DataFrame without a multiindex
inv_cols = inv_multi.reset_index()
print(inv_cols)
store_id product_id stock
0 0 2 48
1 0 4 18
2 0 5 58
3 0 7 149
4 0 8 158
... ... ... ...
6321864 9999 992 132
6321865 9999 995 121
6321866 9999 996 105
6321867 9999 998 99
6321868 9999 999 16
[6321869 rows x 3 columns]
%%timeit
inv_multi.xs(key=100, level='store_id')
10 loops, best of 3: 20.2 ms per loop
%%timeit
inv_cols.loc[inv_cols.store_id == 100]
The slowest run took 8.79 times longer than the fastest. This could mean that an intermediate result is being cached.
100 loops, best of 3: 11.5 ms per loop
%%timeit
inv_multi.xs(key=100, level='product_id')
100 loops, best of 3: 9.08 ms per loop
%%timeit
inv_cols.loc[inv_cols.product_id == 100]
100 loops, best of 3: 12.2 ms per loop
%%timeit
inv_multi.xs(key=(100, 100), level=('store_id', 'product_id'))
10 loops, best of 3: 29.8 ms per loop
%%timeit
inv_cols.loc[(inv_cols.store_id == 100) & (inv_cols.product_id == 100)]
10 loops, best of 3: 28.8 ms per loop
MultiIndexを使用する利点は、構文糖衣、自己文書化データ、およびunstack()
@ZaxRの回答で述べたような関数の小さな便利さです。パフォーマンスはメリットではなく、チャンスを逃したようです。