11. ライブラリの利用

8章でファイル入出力を紹介したが、csv形式のファイルの読み込みは面倒であった。 実際、csvファイルを文字列として読み込んだ後に 2次元リストに変換するような処理をいちいち書くようなことはせず、 Pythonが標準でもつライブラリ(あるいはパッケージ)を使用して ファイル読み込みを行うことが多い。 さらにPythonでは標準ライブラリでない、外部ライブラリの利用も非常に容易に行える。 この章では標準ライブラリの使用方法や前の章で作成した自作のクラス(モジュール)の利用方法と 外部ライブラリのインストール方法や使用方法について紹介する。

11.1 標準ライブラリ

標準ライブラリはその名の通り、Pythonが標準でもつライブラリであり 「import ライブラリ名」で使用できる。

import math
import datetime as dt

PI = math.pi
print(PI)
print(math.sin(PI/6))

a = 60
rad_a = math.radians(a)
print(math.cos(rad_a))

dt_now = dt.datetime.now()
print(dt_now)
print(dt_now.hour)
sample11_01_00_importLib.py

importはスクリプトファイルの先頭にまとめて書くのが一般的である。 (どんなライブラリを使用しているかがすぐに分かるようにするため。) mathライブラリは数学関係の処理を行える。 datetimeライブラリは日付を扱うことができる(detetime型を扱える)。 なお、上記例ではdatetimeだと長いのでasを用いてdtとおいている。

4行目ではmathライブラリ内にある変数piを呼び出し、 6行目ではmathライブラリ内にある関数sin()を呼び出している。 ドット"."を用いて下の階層にアクセスしているようなイメージを持つと良い。 (0章のパッケージ・モジュールなどの階層図参照。) 9行目のradians()は度をラジアンに変更する関数である。 12行目はdt(datetime)ライブラリ[パッケージ]内の datetimeパッケージ[モジュール]内のnow()関数を呼び出している。 (パッケージ名・モジュール名がともにdatetimeであるため紛らわしいかもしれない。 import時にasを用いなければ「datetime.datetime.now()」と書くことになる。)

datetimeライブラリの中身をもう少し詳しくみていく。

    datetime
  • date: 年月日(xxxx/xx/xx)
  • time: 時刻(xx:xx:xx.xx)
  • datetime: 年月日 + 時刻
  • timedelta: 日付の計算
さらにこれらの型(クラス)の中に関数や変数が入っている。

import datetime

print(datetime.date)                # -> <class 'datetime.date'>
date_today = datetime.date.today()  # 今日の日付取得
print(date_today.isoformat())       # ISOフォーマット(文字列)
print(date_today.year, date_today.month, date_today.day)

print(datetime.datetime)                         # -> <class 'datetime.datetime'>
dt_now = datetime.datetime.now()                 # 現在時刻取得
print(dt_now)                                    # datetimeクラス
print(dt_now.isoformat())                        # ISOフォーマット(文字列)
print(dt_now.strftime("%Y-%m-%D (%A) %H:%M:%S")) # 書式フォーマット指定(文字列)

one_day = datetime.date(2021, 3, 5)              # 日付定義
dlt_day = one_day + datetime.timedelta(days=50)  # 日付加算
print(dlt_day, dlt_day.weekday())                # 月:0、火:1、…
sample11_01_01_datetime.py

毎回「datetime.xxx」と書くのは手間である。 そこで「from ライブラリ名 import モジュール名」の書くと 「datetime.」を省略できる

from datetime import datetime, date, timedelta

print(date)
date_today = date.today()
print(date_today.isoformat())
print(date_today.year, date_today.month, date_today.day)

print(datetime)
dt_now = datetime.now()
print(dt_now)
print(dt_now.isoformat())
print(dt_now.strftime("%Y-%m-%D (%A) %H:%M:%S"))

one_day = date(2021, 3, 5)
dlt_day = one_day + timedelta(days=50)
print(dlt_day, dlt_day.weekday())
sample11_01_02_fromImport.py

「from ライブラリ名 import *」と書くとライブラリ内にある全てのモジュールがインポートされる。 しかし、このやり方だと実際に使われるモジュールが何かが分かりにくくなるため非推奨とされている(PEP8)。

第8章ファイル入出力の学習の際にcsv形式のファイルを読み込んだ。 この際にカンマを区切り文字としsplit(',')で文字列を分割するという面倒な手法を紹介したが、 Pythonには「csv」という標準ライブラリが存在し、これを用いることで簡単に2次元リストを作ることができる。

import csv

with open('sample_data1.txt', encoding='UTF-8') as f:
    r = csv.reader(f)
    for row in r:
        print(row)

# 2次元リストに格納する(内包表記利用)
with open('sample_data1.txt', encoding='UTF-8') as f:
    r = csv.reader(f, delimiter=',')
    data = [row for row in r]
print(data)
sample11_01_03_csv.py

delimiterでは区切り文字を指定できる。 delimiterはデフォルトで','が設定されている為、csv形式のファイルの読み込みの際は省略しても問題ない。 一方でtsv形式を読み込みたいときは「delimiter='\t'」としてタブを区切り文字に指定する必要がある。 csvライブラリを用いずに読み込んだ際(第8章参照)は、 split(',')での分割や改行コードの削除などをいちいち書く必要があったがライブラリを用いることで 非常に簡単に読み込めることが分かるだろう。 このcsvライブラリのように処理を簡単に行ってくれるライブラリは多種多様に存在する為、 上手く利用してやると良いだろう。

csvライブラリにはwrite関数も実装されており、2次元リストを容易に保存することもできる。 csvファイルは人間にも読める形式ではあるが、コンピュータ(Python)で読み込むには型の変換であったり、 文字コードなどを気にする必要がある。 その面倒さを解決するためにPythonではオブジェクトそのものを保存できる「pickle」という標準ライブラリが存在する。 pickleはオブジェクトをバイナリデータとして保存することで、 データを再利用する際に型変換が必要なくなるので読み込みが高速化されるという利点がある。

import csv
import pickle as pkl

def str2int(s):
    try:
        return int(s)
    except:
        return s

# csv.readerで読み込み2次元リスト化
with open('sample_data1.txt', encoding='UTF-8') as f:
    reader = csv.reader(f, delimiter=',')
    data = [r for r in reader]

#print(data)

# 辞書データひな形
dict_data = {
    'id': [], '氏名': [], 'class': [], '数学': [], 
    '英語': [], '理科': [], '社会': [],  '国語': []
}

# 辞書型のデータに書き換え(ヘッダー名: 列データリスト)
for row in data[1:]:
    idx = 0
    for k in dict_data:
        dict_data[k].append(str2int(row[idx]))
        idx += 1

# print(dict_data)
# print(sum(dict_data['数学'])/len(dict_data['数学']))

with open('pkl_test.pkl', mode='wb') as f:
    pkl.dump(dict_data, f)

'''
with open('pkl_test.pkl', mode='rb') as f:
    data = pkl.load(f)
print(data)
'''
sample11_01_04_pkl.py

上記例にあるように保存はpickle.dump(オブジェクト, ファイル)で行える。 open()の際にはmode='wb'でwは書き込み、bはバイナリを表している。 コメントアウトしてあるが、読み込みはpickle.load(ファイル)で行える。 (pickleは外部ライブラリpandasを扱う際に用いるかもしれないのでここで紹介しておいた。)

よく用いる標準ライブラリ

標準ライブラリ名 用途
datetime 基本的な日付型および時間型
glob Unix 形式のパス名のパターン展開
math 数学関数
os 雑多なオペレーティングシステムインターフェース
random 擬似乱数を生成する
re 正規表現操作
shutil 高水準のファイル操作
time 時刻データへのアクセスと変換
urllib URLを扱うモジュール群
この中でも「import os」はファイル操作やディレクトリ操作を扱えるので頻出する。 「shutil」モジュールはosモジュールの拡張版みたいなものでPython3.4から利用できる。 (osでは出来なくて、shutilでは出来る操作もあれば、 shutilでは出来なくて、osでは出来る操作もある。 ややこしいのでまとめて欲しいというのが主観である。)

11.2 ユーザー定義クラスのimport

前章でmyclassinput.pyファイルを保存し、その中にInputNumberクラスを作成した。 このように自作したクラスやモジュールもimportすることでその別のpyファイルで利用できる。 (myclassinput.pyは同じディレクトリにある必要がある。) 書き方は「import 自作クラスのファイル名」、fromを用いる場合は「from 自作クラスのファイル名 import クラス名」である。

from datetime import date, timedelta
from myclassinput import InputNumber

WEEK_LIST = ['月', '火', '水', '木', '金', '土', '日']

inputN = InputNumber()                     # InputNumberオブジェクト(クラス)を代入
# InputNumber内のinput_int関数を利用
input_year = inputN.input_int('year >')     # 入力:年
input_month = inputN.input_int('month >')   # 入力:月
input_day = inputN.input_int('day >')       # 入力:日

# date型生成
input_date = date(input_year, input_month, input_day)
weeknum = input_date.weekday()                # 曜日番号取得
date_str = input_date.strftime('%Y年%m月%d日') #3.6だとバグっぽい?
print('{}は{}曜日です。'.format(date_str, WEEK_LIST[weeknum]))
sample11_02_00_importUsersClass.py

ユーザーモジュールのimport

上記でInputNumberクラスをインポートしたが、 このInputNumberクラスはクラスである必要性があまりない。 (インスタンスを作らないのであればクラスにするのは良くない気がする。) myclassinput.pyをクラス化せず、モジュール化したmymoduleinput.pyで十分である。 これを呼び出すには、「import 自作moduleのファイル名」で行える。

from datetime import date, timedelta
import mymoduleinput as myinput

WEEK_LIST = ['月', '火', '水', '木', '金', '土', '日']

# mymoduleinput内のinput_int関数を利用
input_year = myinput.input_int('year >')     # 入力:年
input_month = myinput.input_int('month >')   # 入力:月
input_day = myinput.input_int('day >')       # 入力:日

# date型生成
input_date = date(input_year, input_month, input_day)
weeknum = input_date.weekday()                # 曜日番号取得
date_str = input_date.strftime('%Y/%m/%d')
print('{}は{}曜日です。'.format(date_str, WEEK_LIST[weeknum]))
sample11_02_01_importUsersModule.py

なお、mymoduleinput.pyファイルをフォルダ"mymodules"に入れたとすれば importには「import mymodules.mymoduleinput」のように「import フォルダ名.ファイル名」 のように書く。

  • working_dir
    • usemymodule.py
    • mymodules
      • mymoduleinput.py

自作したモジュールを(異なるディレクトリにある)複数のファイルから呼び出したいときに、 毎回その作業ディレクトリ内にモジュールファイルを配置するのは面倒である。 そこで、複数の実行ファイルで使いたいときには、 デフォルトのパッケージディレクトリに配置すると良い。 具体的な配置場所は場所は以下で確認できる。

>>>import sys
>>>print(sys.path)
デフォルトのパッケージディレクトリ

"Lib"というフォルダが存在すると思うので、そこに"mymodules"フォルダを置く。 配置した"mymodules"フォルダ内に"mymoduleinput.py"とファイル名が"__init__.py"で 中身は空のファイルを作成しておく。 これで自作モジュールもPythonの標準ライブラリと同等に扱え、どこからでも呼び出せるようになる。

11.3 外部ライブラリ

ファイル入出力の際にみたcsv形式のデータの扱いは面倒だった。 このようにPython標準だと面倒であったり、処理が遅かったりする部分を解決するために サードパーティーが作ってくれているライブラリがあり、 これらは個別にインストールすることで利用できる。 ここでは外部ライブラリのインストールから基本的な利用方法を説明する。

外部ライブラリのインストール

外部ライブラリのインストールする方法は大きく分けて3つある。

  1. 「pypi」を用いる方法
  2. 「github」からインストールする方法
  3. 「whlファイル(ZIP形式のアーカイブファイル)」からインストールする方法
実際のところ覚えておくべきは、3つではなく1つでよく、ほぼ(A)の方法しか用いない。 (B)はpypiに登録されていないようなマイナーなパッケージを入れたいときに使ったりする (パッケージの最新バージョンのベータ版などはgithub上においてあったりする)。 (C)は本当に使わない。 オフラインでパッケージを渡すときに用いるのだが、 (A)でエラーがでた際の最終手段ぐらいの認識で良い。

「pypi」は「Python Package Index」の略であり、 「pipコマンド」を用いることでコマンドプロンプトでパッケージを管理できる (Python Package Indexのネットからパッケージをダウンロード・インストールすることや アップデート、アンインストールを容易に行える)。 pypiには35万以上のパッケージが登録されいる(2021/12時点)が、 取り敢えずここでは「numpy」と呼ばれる数値計算を高速に行えるパッケージをインストールする。

コマンドプロンプトを開き「pip install numpy」と入力する。 以上である。後はpipが自動でやってくれる。 さすがに味気なさすぎるので、他のコマンドも紹介しておく。
コマンド 説明
pip install numpy 最新バージョンのインストール
pip install numpy==1.20.1 バージョン指定してインストール
pip install -U numpy インストール済みライブラリのアップデート
pip uninstall numpy アンインストール
pip list インストール済みライブラリを表示
pip list -o アップデート可能なライブラリを表示
pip install -U pip pip自体のアップデート
この他にも「freeze」など便利なコマンドが多数存在する。 また、「pip install -U pip」で定期的にpip自体をアップデートしないと 警告が表示される。 pipは新しいバージョンが短いスパンで出ているような気がする。

※「venv」などで作った仮想環境でもpipは使える。 Pythonで何か開発し、さらに配布しようとするなら仮想環境の構築はやっておいた方が良い。 仮想環境をつくらないとインストールしたライブラリが Pythonのメインシステムに大量に入って来ることになり、パッケージ間の 依存関係などが意味が分からなくなる。

外部ライブラリのimport

インストールさえしてしまえば、外部ライブラリも標準ライブラリと同様にimportして扱える。 以下はnumpyを利用したプログラムである。

import numpy as np      #npとして扱うことが多い

print(np.pi)
print(np.sin(np.pi/2))

x = np.array([0, 1, 2, 3, 5, ,7 ,9, 3, ,5])
print(x.var(), x.std())

print(np.sin(np.pi/x))
sample11_03_00_importExternalLibrary.py

外部ライブラリの例としてnumpyを挙げたが、numpyは数値計算を行う際にはもはや必須である。 このライブラリがあるからPythonが解析プログラム言語として活躍できている。 numpy以外にも入れておいた方が良いライブラリがいくつかあるので紹介する。

よく用いる外部ライブラリ(データ解析)

外部ライブラリ 説明
NumPy 行列計算を含めた数値計算を高速に行える。 多くの関数が実装されており便利。むしろ、科学計算においてnumpyは必須。
SciPy numpyの拡張ライブラリ。 特殊関数や物理定数(光速・プランク定数など)が実装されている。 また方程式の数値解を求められる。
matplotlib グラフ作成ライブラリ。 2次元だけでなく3次元プロットも可能。 アニメーションも作成できる。 numpyと一緒に使うと関数のプロットとかができる。 seabornという拡張ライブラリもある。
pandas データ解析を高速で行える。データフレーム型を提供し、 時系列データ解析・グループ化・pivotテーブルなどを扱える。 データファイル(csvやtsvファイル)を読み込んで何か処理したいときはだいたいこれ使う。 扱うのに少し慣れがいるが、慣れれば便利。
SymPy 数式処理システム(記号演算)を行える。 numpy(scipy)が数値計算を行うのに対して、Sympyは理論計算を行う。 微積分・方程式・行列なども扱える。 Tex表記での出力も可能でJupyter(Google Colaboratory)と相性が良い。
「NumPy」、「matplotlib」、「pandas」は3種の神器である。 (+SciPyの4つのライブラリはデータ解析を行う際は最低でも入れておきたい。)

上記の例以外にも画像解析を行う「OpenCV」やスクレイピングが容易にできる「beautifulsoup4」 Excelを読み込む「xlrd」、ネット接続を容易にする「requests」、 対話型インタプリタを拡張した「ipython」など目的に応じて欲しいライブラリをインストールすればよい。 なお、流行しているAIの分野をみると、機会学習なら「scikit-learn」、 深層学習(ニューラルネットワーク)なら「Tensorflow」などが有名である。 これら2つとも開発元がGoogleである。 ときどき、「PythonはAIの分野で広く使われる」のような文を見かけるが、これは正確ではなく 「PythonはTensorflowなどのニューラルネットワークを提供するライブラリを手軽にインストールできる」と言う方が良いだろう。 (Tensorflow自体はCやJavaでも問題なく使える。それらはインストールなどの準備が面倒であるが、 Pythonならpip tensorflowで完結する。)

Pythonの利点である豊富な外部ライブラリの存在は、Pythonの学習にとっては非常に不利である。 Pythonの標準装備だけでプログラムを書くだけであれば簡単なのだが、 外部ライブラリを利用しないとPythonの利点が活かせなくなる。 つまり、大量にあるライブラリの使い方をそれぞれ学ばないといけなくなる。 (ライブラリ使わないならCで書けばよいのでは?となる。その方が処理も速いので。) ネット上に転がっているPythonのコードを見てみるとよい。 コード全体に対しての半分以上の行では、何かしらのライブラリを用いた処理をしていることであろう。

[私的メモ] numpyとmatplotlibについては書きたい。 pandasは余裕があれば書け。 一番pandasの書き方が特殊だろ。 numpyとmatplotlibさえどうにか書ければデータ解析はできるはず。