CUBE SUGAR CONTAINER

技術系のこと書きます。

Python: pandas で縦持ちのデータを横持ちにする

データ処理の世界では、データの持ち方に縦持ちと横持ちという考え方がある。 縦持ちでは、レコードに種類といったカラムを持たせてデータを追加していく。 それに対し横持ちでは種類ごとにカラムを用意した上でデータを追加する形を取る。 一般的にはデータの持ち方としては縦持ちのものが多いと思う。 今回は pandas で縦持ちのデータを横持ちに直す方法について書く。

使った環境は次の通り。

$ sw_vers 
ProductName:    Mac OS X
ProductVersion: 10.13.4
BuildVersion:   17E202
$ python -V    
Python 3.6.5

下準備

まずは pandas をインストールしておく。

$ pip install pandas

続いて Python のインタプリタを起動する。

$ python

あとは縦持ちの形式になったサンプルの DataFrame オブジェクトを用意する。 今回は、時系列データで商品が売れた数っぽいものを用意した。

>>> import pandas as pd
>>> data = [
...     ('2018-05-30 20:00:00', 'Onigiri', 1),
...     ('2018-05-30 20:00:00', 'Pan', 2),
...     ('2018-05-30 20:00:00', 'Pasta', 1),
...     ('2018-05-30 20:00:10', 'Onigiri', 3),
...     ('2018-05-30 20:00:20', 'Pan', 2),
...     ('2018-05-30 20:00:30', 'Pasta', 1),
...     ('2018-05-30 20:01:00', 'Onigiri', 2),
...     ('2018-05-30 20:01:00', 'Pan', 2),
...     ('2018-05-30 20:01:00', 'Pasta', 2),
... ]
>>> columns = ['datetime', 'code', 'amount']
>>> df = pd.DataFrame(data, columns=columns)
>>> df = df.assign(datetime = pd.to_datetime(df.datetime, format='%Y-%m-%d %H:%M:%S'))

出来上がる DataFrame はこんな感じ。

>>> df
             datetime     code  amount
0 2018-05-30 20:00:00  Onigiri       1
1 2018-05-30 20:00:00      Pan       2
2 2018-05-30 20:00:00    Pasta       1
3 2018-05-30 20:00:10  Onigiri       3
4 2018-05-30 20:00:20      Pan       2
5 2018-05-30 20:00:30    Pasta       1
6 2018-05-30 20:01:00  Onigiri       2
7 2018-05-30 20:01:00      Pan       2
8 2018-05-30 20:01:00    Pasta       2
>>> df.dtypes
datetime    datetime64[ns]
code                object
amount               int64
dtype: object

横持ちにする

それでは上記を横持ちに直してみる。 pandas でデータを横持ちにするときは DataFrame#pivot_table() を使う。

インデックスには時刻 (datetime) を、集計対象は売れた数 (amount)、カラムの種類は商品 (code) でテーブルを組んでみよう。 集計用の関数には加算 (sum) を指定している。 fill_value オプションを指定しておくと、値が存在しないときにそれで埋めてくれる。

>>> df.pivot_table(values=['amount'], index=['datetime'], columns=['code'], aggfunc='sum', fill_value=0)
                     amount          
code                Onigiri Pan Pasta
datetime                             
2018-05-30 20:00:00       1   2     1
2018-05-30 20:00:10       3   0     0
2018-05-30 20:00:20       0   2     0
2018-05-30 20:00:30       0   0     1
2018-05-30 20:01:00       2   2     2

いいかんじ。

それぞれのオプションを変えるとテーブルの形を変えられる。 例えばインデックスを指定しない場合は上記から時系列情報が抜ける。

>>> df.pivot_table(values=['amount'], columns=['code'], aggfunc='sum')
code    Onigiri  Pan  Pasta
amount        6    6      4

インデックスを商品にすれば縦横が入れ替わる。

>>> df.pivot_table(values=['amount'], index=['code'], aggfunc='sum')
         amount
code           
Onigiri       6
Pan           6
Pasta         4

まあ、とはいえ上2つのような集計なら DataFrame#groupby() でも十分かな。

>>> df.groupby('code').sum()
         amount
code           
Onigiri       6
Pan           6
Pasta         4

めでたしめでたし。

Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理

Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理

前処理大全[データ分析のためのSQL/R/Python実践テクニック]

前処理大全[データ分析のためのSQL/R/Python実践テクニック]