Pandas DataFrame のX軸の単位を調整する

内容

DataFrame で histogram を描画したときの x, y 軸のスケールの表示を調整する方法について、ハマったのでメモとして残しておきます。

TL;DR

DataFrame から直接 df.hist とするのではなく、
一度、 df.plotmatplotlib.axes._subplots.AxesSubplot を取り出し、
その matplotlib.axes._subplots.AxesSubplotticklable_formatstyle オプションを変更することで整数表示や浮動小数点表記での表示などを指定することができます。

ax = sample_df.plot(figsize=(15, 5), kind='hist', bins=100)
ax.ticklabel_format(style='plain', axis='x') # 浮動小数点表記で表示したい場合、 style='sci' とする

Pandas の version

0.24.1 を使ってます。

import pandas as pd
pd.__version__
'0.24.1'

どういう事象?

元々、データ分析の案件で発生した事象で、
少数を含む、かつ、取りうる値の範囲が広いデータを DataFrame で扱い、それを df.hist で描画しようとしました。

今回は、だいたいのデータとして、以下のデータで再現実験をします。

sample_size = 10000
sample_data = np.random.rand(sample_size)
sample_data = [d * np.random.randint(low=1, high=10000000) for d in sample_data]
sample_category = ["a_{}".format(i) for i in range(sample_size)]
d = {'col1': sample_category, 'col2': sample_data}
sample_df = pd.DataFrame(d)

以下のようなデータが作成されます。

pd.options.display.float_format = '{:.2f}'.format
sample_df.head(10)

    col1    col2
0  a_0     6809432.40
1  a_1     3095277.45
2  a_2     1515776.87
3  a_3     6291255.66
4  a_4     429976.20
5  a_5     422715.54
6  a_6     5695883.51
7  a_7     2793741.89
8  a_8     2343652.35
9  a_9     4571542.77

分布としては、以下のような感じ。

sample_df.describe()

        col2
count   10000.00
mean    2498833.72
std         2212640.08
min  128.83
25%    662876.83
50%    1854733.14
75%    3875713.08
max  9861186.18

桁のオーダを見ると 102 から 106 のデータが生成されています。
このデータを df.hist で描画すると

f:id:toohsk:20190401105232p:plain
x軸が浮動小数点表記表示になっている histogram

のような形式になりました。 X 軸のスケールに注目すると自動的に浮動小数点表記に変換されていることがわかります。

今回のようなランダムに生成されたデータの場合、このような表現でもわかりますが、
この結果を他の方にシェアする場合、実際の値としてみた方が感覚をつかみ安い方もいるかと思います。

どうやって整数表示にするか

x, y 軸の表示に関する操作はどうやら matplotlib.axes.Axes class にて操作することは調べて想定がつきました。
ただ、問題なのは、 df.hist で返される値の型は numpy.ndarray でした。

hist = sample_df.hist(bins=100, figsize=(15, 5))
type(hist)

numpy.ndarray

なので、 matplotlib.axes.Axes class を操作しようとしても操作できず、 軸のスケールを操作することができません。

なので、 histogram の描画を df.hist で行うのではなく、
df.plot で描画し、 option の kind で kind='hist' とすることで、 matplotlib.axes.Axes class を戻り値として受け取れるようにしました。

ax = sample_df.plot(figsize=(15, 5), kind='hist', bins=100)
type(ax)

matplotlib.axes._subplots.AxesSubplot

これにより、目的だった matplotlib.axes.Axes class を操作することができました。 matplotlib.axes.Axes class の ticklabel_formatstyle='plain とすることで軸のスケールを整数表示することができました。

ax = sample_df.plot(figsize=(15, 5), kind='hist', bins=100)
ax.ticklabel_format(style='plain', axis='x') # axis='y' とすると y 軸のスケールを整数にすることができる

f:id:toohsk:20190401111909p:plain
x軸が整数表示になっている histogram

反対に、明示的に浮動小数点表記としたい場合は、 ticklabel_format の style オプションを style=sci とすればよく、
y 軸のスケールを変えたい場合は、 ticklabel_format の axis オプションを axis=y とすればよいみたいです。