linuxBean14.04(76)MySQL5.6からPython3.4で散布図をプロットする

ラベル: ,

前の関連記事:linuxBean14.04(75)matplotlibのインタラクティブなグラフ


Graph data from a MySQL database in Python | Modern Dataと似たようなことをやります。linuxBean14.04(69)MySQL5.6にPython3.3から接続するでやったようにMySQL5.6にサンプルデータベースworld databaseのインストールした状態から開始します。

mysql-connector-pythonのインストール


まずlinuxBean14.04(72)Anacondaで科学技術系Pythonパッケージを一括インストールするでインストールしたAnacondaのPython3.4でMySQL5.6のConnector/Pythonが使えるようにします。

conda search mysql-connector-python
pq@pq-VirtualBox:~$ conda search mysql-connector-python
Fetching package metadata: ....
mysql-connector-python       2.0.3                    py35_0  defaults        
                             2.0.3                    py34_0  defaults        
                             2.0.3                    py33_0  defaults        
                             2.0.3                    py27_0  defaults        
                             2.0.3                    py26_0  defaults 
py34に対応したmysql-connector-pythonのcondaパッケージがみつかりました。

linuxBean14.04(64)MySQL Utilities1.5.5とConnector/Python2.0.4のインストールでは2.0.4でしたがこのままcondaで2.0.3をインストールしてしまいます。

conda install mysql-connector-python

これでmysql-connector-python 2.0.3がインストールできました。

matplotlibのグラフで日本語フォントが表示されるようにする


デフォルトの設定でグラフに日本語を出力させようとすると□□□と文字化けして表示されてしまいます。

Python - matplotlib によるデータ可視化の方法 (1) - Qiitamatplotlib.font_manager.FontProperties()クラスを使ってフォントを指定する方法が載っていますが、Python - matplotlibで日本語 - Qiitaの使い方を見ていると逐一フォント指定がいるようです。

【matplotlib】日本語の設定 - keisukeのブログの一括してフォント設定する方法をやってみました。
import matplotlib
matplotlib.matplotlib_fname()

matplotlibrcファイルが~/anaconda3/lib/python3.4/site-packages/matplotlib/mpl-dataにあることがわかります。

まずこのフォルダの下層にある~/anaconda3/lib/python3.4/site-packages/matplotlib/mpl-data/fonts/ttfフォルダを開きます。

linuxBean14.04(25)NetBeans8とLibreOffice5のインストールと同様にしてこのフォルダにTakaoフォントへのシンボリックリンクを作成します。

ln -s /usr/share/fonts/truetype/takao-gothic/Takao* .


ttfファイルのシンボリックリンクが作成されました。

フォント指定にはフォント名が必要ですので次のコマンドでフォント名を調べておきます。

fc-list | grep Takao
pq@pq-VirtualBox:~/anaconda3/lib/python3.4/site-packages/matplotlib/mpl-data/fonts/ttf$ fc-list | grep Takao
/usr/share/fonts/truetype/takao-mincho/TakaoExMincho.ttf: TakaoEx明朝,TakaoExMincho:style=Regular
/usr/share/fonts/truetype/takao-mincho/TakaoPMincho.ttf: Takao P明朝,TakaoPMincho:style=Regular
/usr/share/fonts/truetype/fonts-japanese-gothic.ttf: Takao Pゴシック,TakaoPGothic:style=Regular
/usr/share/fonts/truetype/takao-gothic/TakaoExGothic.ttf: TakaoExゴシック,TakaoExGothic:style=Regular
/usr/share/fonts/truetype/arphic/uming.ttc: Takao Pゴシック,TakaoPGothic:style=Regular
/usr/share/fonts/truetype/fonts-japanese-mincho.ttf: Takao P明朝,TakaoPMincho:style=Regular
/usr/share/fonts/truetype/takao-gothic/TakaoPGothic.ttf: Takao Pゴシック,TakaoPGothic:style=Regular
/usr/share/fonts/truetype/takao-gothic/TakaoGothic.ttf: Takaoゴシック,TakaoGothic:style=Regular
/usr/share/fonts/truetype/takao-mincho/TakaoMincho.ttf: Takao明朝,TakaoMincho:style=Regular
TakaoExGothic.ttfはTakaoExGothic、TakaoGothic.ttfはTakaoGothic、TakaoPGothic.ttfはTakaoPGothicとわかります。

ファイルマネージャで~/anaconda3/lib/python3.4/site-packages/matplotlib/mpl-data/fonts/ttfフォルダを開いてツール→現在のフォルダを端末で開く。

ln -s /usr/share/fonts/truetype/takao-gothic/Takao* .

~/anaconda3/lib/python3.4/site-packages/matplotlib/mpl-dataにあるmatplotlibrcファイルを編集します。

編集前にmatplotlibrc.oriといったコピーを作って元ファイルのバックアップをとっておきます。
font.family:TakaoGothic
matplotlibrcファイルの155行目の空行にTakaoGothicを指定しました。

Jupyter Notebookの場合はrestar kernelボタンをクリックしてClear all output & restartボタンをクリックしてkernelを再スタートすると変更したフォントが反映されました。

TakaoGothic

TakaoExGothic

TakaoPGothic

うーん、違いがよくわからないのでとりあえずTakaoGothicを使うことにしました。

pandasを0.17.0にアップデートする


次に使う予定のpandasからSQL文を実行するpandas.io.sqlパッケージが変更になっているようなのでまずpandasを0.17.0にアップデートします。(What’s New — pandas 0.17.0 documentation
pq@pq-VirtualBox:~$ conda list pandas
# packages in environment at /home/pq/anaconda3:
#
pandas                    0.16.2               np19py34_0  
pq@pq-VirtualBox:~$ conda update pandas
Fetching package metadata: ....
Solving package specifications: .
Package plan for installation in environment /home/pq/anaconda3:

The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    numpy-1.10.0               |           py34_0         5.3 MB
    requests-2.8.0             |           py34_0         629 KB
    six-1.10.0                 |           py34_0          17 KB
    conda-3.18.1               |           py34_0         176 KB
    pandas-0.17.0              |      np110py34_0        13.5 MB
    ------------------------------------------------------------
                                           Total:        19.6 MB

The following packages will be UPDATED:

    conda:    3.17.0-py34_0     --> 3.18.1-py34_0     
    numpy:    1.9.3-py34_0      --> 1.10.0-py34_0     
    pandas:   0.16.2-np19py34_0 --> 0.17.0-np110py34_0
    requests: 2.7.0-py34_0      --> 2.8.0-py34_0      
    six:      1.9.0-py34_0      --> 1.10.0-py34_0     

Proceed ([y]/n)? y
これでpandas0.16.2がpandas0.17.0にアップデートできました。

MySQL5.6サーバからPython3.4で取得したデータをpandasのデータフレーム型にする


#!~/anaconda3/bin/python3.4
# -*- coding: utf-8 -*-
import mysql.connector
from mysql.connector import errorcode
config = {
    'user': 'User01',
    'password': 'user01_pass',
    'database': 'world'
}
try:
    cnx = mysql.connector.connect(**config)
except mysql.connector.Error as err:
    if err.errno == errorcode.ER_ACCESS_DENIED_ERROR:
        print("ユーザー名かパスワードが間違っています。")
    elif err.errno == errorcode.ER_BAD_DB_ERROR:
        print("データベース「{}」が存在しません。".format(config['database']))
    else:
        print(err)
else:
    cursor = cnx.cursor()
    query = 'SELECT Name, Continent, Population, LifeExpectancy, GNP FROM Country'
    cursor.execute(query)
    for (Name, Continent, Population, LifeExpectancy, GNP) in cursor:
        print("{}, {}, {}, {}, {}".format(Name, Continent, Population, LifeExpectancy, GNP))
    cursor.close()
    cnx.close()
linuxBean14.04(69)MySQL5.6にPython3.3から接続するで作ったコードがそのまま使えました。
    cursor.execute(query)
    rows = cursor.fetchall()
    cursor.close()
    cnx.close()
import pandas as pd
df = pd.DataFrame(rows)
df.rename(columns={0: '国', 1: '大陸', 2: '人口', 3: '平均余命', 4:'国民総生産'}, inplace=True)
23行目以下を書き換えました。

23行目でSQLで得られたテーブルの各行をMySQLCursor.fetchall()メソッドで2次元のタプルでrowsに取得しました。


rowsは(国、大陸、人口、平均余命、国民総生産)のタプルのタプルになっています。

27行目でpandas.DataFrame()でrowsをpandasのデータフレーム型に変換しています。


これで239行x5列のデータフレームが得られました。

でもPythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理のp203を読んでpandasを使ってもっと簡単にsqlが実行できることがわかったので書き直します。(以下pで表示してある頁数はこの本のものです。)
else:
    import pandas as pd
    query = 'SELECT Name, Continent, Population, LifeExpectancy, GNP FROM Country'
    df=pd.read_sql(query,cnx)
    df.rename(columns={'Name': '国', 'Continent': '大陸', 'Population': '人口', 'LifeExpectancy': '平均余命', 'GNP':'国民総生産'}, inplace=True)
    cnx.close()
19行目の以降でpandas.read_sqlにselect文と接続オブジェクトcnxを渡すだけで済みます。

cursor.fetchall()で取得した場合と違って列名がすでについています。

pandas.DataFrame.dropna(p164 5.4欠損値の取り扱い)を使って欠損値がある行を削除しておきます。
df.dropna(inplace=True)
これで239行から222行に減りました。

次からはJupyter Notebookで散布図をプロットしていきます。

In [1]:
#!~/anaconda3/bin/python3.4
# -*- coding: utf-8 -*-
import mysql.connector
from mysql.connector import errorcode
config = {
    'user': 'User01',
    'password': 'user01_pass',
    'database': 'world'
}
try:
    cnx = mysql.connector.connect(**config)
except mysql.connector.Error as err:
    if err.errno == errorcode.ER_ACCESS_DENIED_ERROR:
        print("ユーザー名かパスワードが間違っています。")
    elif err.errno == errorcode.ER_BAD_DB_ERROR:
        print("データベース「{}」が存在しません。".format(config['database']))
    else:
        print(err)
else:
    import pandas as pd
    query = 'SELECT Name, Continent, Population, LifeExpectancy, GNP FROM Country'
    df=pd.read_sql(query,cnx)
    df.rename(columns={'Name': '国', 'Continent': '大陸', 'Population': '人口', 'LifeExpectancy': '平均余命', 'GNP':'国民総生産'},inplace=True)
    cnx.close()
In [2]:
df.dropna(inplace=True)

pandasのデータフレームのメソッドでプロットする

Plotting — pandas 0.17.0 documentationpandas.DataFrame.plotを使ったデータフレームのプロットの例が載っています。
In [3]:
df.plot(x='国民総生産',y='平均余命',kind='scatter',figsize=(12,8),title='平均余命 対 国民総生産',grid=True,logx=True,xlim=(100,20000000),fontsize=15,s=df['人口']/100000,alpha=0.5)
Out[3]:
<matplotlib.axes._subplots.AxesSubplot at 0xafd941cc>
/home/pq/anaconda3/lib/python3.4/site-packages/matplotlib/collections.py:590: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
  if self._edgecolors == str('face'):
マーカーの大きさは人口に比例するようになっています。
リファレンスをたどっていろいろ調べてみましたがタイトルとか軸のラベルのフォントの大きさの設定方法がわかりませんでした。
引数にあるfontsize=15というのは目盛りラベルのフォントの大きさの設定です。
xlimでx軸の範囲を設定しないとマーカーが偏ったプロットしか得られませんでした。
FutureWarningという警告がでてくるのですが解決できませんでした。

matplotlibでプロットする

先ほどのpandasのデータフレームのplotメソッドもmatplotlibを使ってプロットしているのですが、今度は直接matplotlibのplotメソッドを使ってプロットします。
In [4]:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(12, 8))
ax.grid(True)
ax.scatter(x=df['国民総生産'],y=df['平均余命'],s=df['人口']/100000,alpha=0.5)
ax.set_xlim((100,20000000))
ax.set_xlabel('国民総生産',size=15)
ax.set_xscale("log")
ax.set_ylabel('平均余命',size=15)
ax.set_title('平均余命 対 国民総生産', size=20)
ax.tick_params(labelsize=15)
plt.show()
/home/pq/anaconda3/lib/python3.4/site-packages/matplotlib/collections.py:590: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
  if self._edgecolors == str('face'):
また同じFutureWarningがでています。matplotlib/collections.pyが原因なので当然のことですが。
set_xlabel、set_ylabel、set_titleで先ほどできなかったフォントサイズの設定を行っています。
それ以外はDataframe.plot()と同じ設定になります。

matplotlibでプロットしたほうがフォントサイズとか設定できることが多いようです。

参考にしたサイト


MySQL :: MySQL Connector/Python Developer Guide
MySQLをPythonから使えるようにするMySQL Connector/Python。

Graph data from a MySQL database in Python | Modern Data
MySQLdbとPlotlyを使ってMySQLからインタラクティブなプロットを出力しています。

Python - matplotlib によるデータ可視化の方法 (1) - Qiita
matplotlibで日本語を使うための設定の例があります。

Python - matplotlibで日本語 - Qiita
matplotlibで日本語を使うための設定の例があります。

【matplotlib】日本語の設定 - keisukeのブログ
matplotlibの設定ファイルで日本語フォントを設定する方法。

What’s New — pandas 0.17.0 documentation
pandas.io.dataパッケージが廃止されました。

pandas.DataFrame — pandas 0.17.0 documentation
pandasのデータフレームのアトリビュートとメソッド一覧。

pandas.read_sql — pandas 0.17.0 documentation
このpandas.read_sqlにselect文と接続オブジェクトを渡すとMySQLからデータを取得できます。

pandas.DataFrame.dropna — pandas 0.17.0 documentation
これで欠損値のある行をデータフレームから削除できます。

Plotting — pandas 0.17.0 documentation
pandasのplotによる例がたくさんあります。

pandas.DataFrame.plot — pandas 0.17.0 documentation
pandas.DataFrame.plotですべてのmaplotlibのplotの設定ができるわけではないようです。

PR

0 件のコメント:

コメントを投稿