見出し画像

ゆるいPython [4]

前回からの続きです。


ライブラリ

Pythonのプログラムを理解するときに,「データ構造」と「アルゴリズム」という二つのキーワードを意識することは大きな助けになります。Pythonの場合,データ構造は組み込み型を組み合わせてモデル化したものなので「数値モデル」の仲間です。アルゴリズムは,データ構造を目的の状態に変えるために使われる計算を含めた手順のことを指します。「計算モデル」ですね。
プログラムにしたい課題があるとします。冒頭で見たような酸素残量を計算するような問題なら,数値化の手法も計算方法もあまり難しくなく,比較的簡単にプログラムを作ることができます。モデル化の手法をよく知っているタイプの課題であれば,簡単にPythonのプログラムを使って解決できるのです。
プログラミングで解決される課題の中には,モデル化が難しい問題もあります。課題となるものごとを要素に分け,各々の要素を連続数,離散数に振り分けて行くことが,プログラムの入口となる数値モデルを作るときの基本です。そのようにして数値モデルが作れたとしても,適切なアルゴリズムがないとプログラムで課題を解決できません。一般的に,問題が複雑になればなるほど,制約条件が多くなり,モデル化の難易度は高くなります。
そこで,プログラミングでは既存のモデルを再利用する,ということをよく行います。頭のいい人が作った,良くできたモデルがあるので,それを借用して楽をするのです。
日付のモデルを読み込んで,プログラムで使ってみます。

from datetime import date, timedelta
a_day = date(2100, 2, 28)《》

次に,2100年2月28日の翌日を計算してみます。

one_day = timedelta(days=1)
a_day+one_day

プログラムの実行結果として「datetime.date(2100, 3, 1)」が表示されます。うるう年は4年に1回ですが,100で割り切れて400で割り切れない年はうるう年としない,という追加の制約があります。そのため,2100年はうるう年ではなく,2月28日の翌日は3月1日になるのです。
日付という,私たちが日常触れている「ものごと」を,数値モデルと計算モデルを使ってモデル化するのは,なかなかに大変なことなのです。日付に時間を加えた「日時」をモデル化する場合,困難はさらに増します。インターネットのある現在,時間をプログラムで扱う時は,国際化を前提に考える必要があります。国ごとに異なる時差を考える必要があるのです。Pythonはタイムゾーンを含めた日時を扱うための標準的なモデルを持っています。特別な理由がない限り,これを使えばいいのです。
「出来合いのモデルを使う」ことには大きな利点があるのです。これは,計算を行うときも同じです。
数値モデルを使っていろいろな事象をモデル化するとき,「乱数」という計算モデルをよく使います。乱数は,さいころを振るときや,コンピュータにゲームをさせる時などに使われます。物体を構成する量子の状態を決めるときも乱数が使われることから,ありふれた計算モデルであることがよく分かります。
乱数を計算する,というのは言葉の意味としておかしい気がします。でも乱数は計算することができるのです。まず,乱数の「種」となる数を初期化します。

seed = 1   # 乱数の種を初期化

次に,乱数を作ります。変数に大きな数が代入されていますが,かけ算と割り算の組み合わせだけで乱数が作られているのが分かります。「**」という記号は累乗を,「%」は割り算の余りを計算するための記号です。

a = 1140671485
c = 128201163
m = 2**24
seed = (a*seed+c) % m
seed  # 乱数を表示

この計算プログラムを実行するごとに,最初は「10581448」,「11595891」,「1502322」というように,乱数が生成されてゆきます。
「線形合同法」という計算モデルの名前を知っていれば,ChatGPTを使って上のプログラムとよく似たプログラムを得ることができます。ただし線形合同法で作られる乱数は,ちょっとしたゲームなどに使うのには問題ありませんが,暗号生成のようなクリティカルな場面での利用には向きません。乱数の計算にも仕組みがあり,乱数のモデルにも品質があるのです。
もう少し品質の高い乱数の計算方法として,日本人が考案した「メルセンヌツイスタ」と呼ばれるモデルがあります。Pythonには,この方法を使って乱数を計算するための計算モデルが用意されています。プログラムを読むと,乱数を計算する関数(random)があり,それを読み込んで使っていることが分かります。

from random import random
random()  # 0から1までの乱数を発生する

関数を呼び出す時,括弧の中に数が入らず「()」のようになっているのはなぜでしょうか。乱数を計算するのに,変数となる数が必要ないからです。正確には,先ほどのような「seed(種)」が必要なのですが,この数はPythonの魔法によって巧妙に隠されているため,引数を与える必要がないのです。Pythonは,このような「珠玉の数値モデル」や「達人級の計算モデル」を沢山備えています。
モデルを整理して格納している場所が「ライブラリ」です。その名の通り図書館のようなもので,必要に応じてモデルを読み込んで使います。ライブラリからモデルを読み込むことを「インポート(import)」といいます。

ライブラリとモデル

コンピュータ上で表現されているものごとは,何らかの方法でモデル化されています。例えば,スマホでやりとりする文字は,離散数としてモデル化されています。文字情報を離散モデル化することは,通信技術を使って送受信する上でとても大きな利点があります。文字を数に置き換えることで,通信エラーを補正しやすく,また暗号化もしやすくなるのです。プログラムで扱うという視点からは,計算を行うことによって文字を変換したり,自由に切り貼りするための手順を組み立てやすくなる,というメリットがあることについては,すでに解説しましたね。
インターネットという通信で送受信されるWebページもまた,文字によってモデル化されています。Webページに表示される文章のような文字だけでなく,文字のレイアウトや,差し込まれた画像の位置を決めるのに文字が使われています。文字を使ってレイアウトの情報を表現するために,HTMLと呼ばれる特別な言語が使われます。
HTMLが表現するのはWebページの「構造」です。たとえば,文章は段落が順番に並ぶことによって作られます。段落の中にある箇条書きの項目にも順番があります。段落と段落の間に画像が入り,そのすぐ下には画像を説明する「キャプション」と呼ばれる短い文が入ります。
典型的なWebページには,文章のようなコンテンツの他に,リンクやメニューのようなユーザインターフェースもあります。横や縦に並んだリンクはひとつひとつ要素として見ることができますし,同じ要素を並べることもできます。コンテンツとユーザーインターフェースなど,Webページを構成する要素を記述するのがHTMLが使われる目的の一つです。HTMLには決まった文法があります。詳細については解説しませんが,HTMLはPythonよりもずっと約束事が多く,覚えるのが難しい言葉だと個人的には思っています。Pythonより学びたいと思う人が多いのは,多分,仕事になりやすく,表現の対象が具体的だからでしょう。
HTMLの持つこのような構造に注目すると,必要な部分だけを自動的に抜き出すプログラムを簡単に作ることができます。このような作業は「スクレイピング」と呼ばれています。Pythonのスクレイピングは,ライブラリを使ってWebページを文字列として読み込み,さらにスクレイピング専用のオブジェクトに変換することから始めます。Webページの構造をPythonのプログラムとして扱いやすくするためです。
スクレイピング用オブジェクトを使うと,WebページのHTML上に並べられた要素は,ループで取り出すことができるようになります。画像が100個並んだページから画像だけを取り出す,といった手順を簡単に作れるようになるのです。同じ手順をWebページの数だけくり返せば,同一デザインの1000ページからすべての画像をダウンロードする,というようなことも簡単にできます。
いまやWebは巨大なデータベースです。画像だけでなく,ありとあらゆるデータをWebから収集できます。スクレイピングはデータ収集の上でとても重要な技術です。
表計算ソフトエクセル上のデータも,Webページと同じくファイルに文字として書き出されます。データは,表計算のシートに書き込まれる段階で縦横の表として構造化されています。表自体が一種のデータ構造と呼ぶことができます。表計算ソフトでは表を複数重ねてシートとして管理できますが,これも表を順番に並べたデータ構造と見ることができます。この構造を,文法を持ったXMLという形式に変換することで文字に変え,ファイルに保存しているのです。
Pythonには,ファイルの文字データを読み込み,エクセルのデータ構造を復元してオブジェクトにするライブラリがあります。このライブラリを使うと,エクセルのデータをPythonで操作するプログラムを簡単に作ることができます。Python上で操作したデータを,エクセルのファイルと同じ形式でファイルに保存し直すことで,再度エクセルで開くことができます。手作業で実行している手順をプログラムで自動実行できるようになれば,業務の自動化を行うことができます。
このように,コンピュータ上の情報をプログラムで扱いやすくしてくれるオブジェクトの存在は,Pythonにとってとても大きなものになっています。スクレイピングやエクセルの自動化を目的にPythonを学ぶ人がいるからです。

Pythonの木の歴史

エクセルの自動化やスクレイピングの他にも,Pythonがデファクトスタンダードとなっている分野がいくつかあります。AI(機械学習)はそのような分野の最右翼と呼べるかも知れません。他にも,生命情報科学や製薬,気象予報のような科学技術計算,CGなど,数え上げたらきりがありません。
それぞれすべての分野に,扱いたい課題をPython上で数値モデル化し,モデルを操るための計算モデルを備えたライブラリが存在します。そうして出来上がったのが,最初にみなさんが見たPythonの木です。

誕生当時から,Pythonの木にこんなにたくさんの実がなっていたわけではありません。現在の最新バージョンは3ですが,私がPythonを始めたバージョン1の頃は,もっと実の種類が少なかったのです。その頃のPythonは,だいたいこんな感じでした。

極端に木の実を減らしすぎたようにも感じていますが,伝えたいことはこういうことです。バージョン1当時のPythonは「プログラミングがよく分かった人が,ゆるく手軽にプログラムを作るための道具」でした。
プログラミングを専門にしない人からみると,この「ゆるさ」が「簡単」と写ったのでしょう。そして,コンピュータを使って数値計算をしていた科学者達がPythonに目を向けました。研究者がやりたかったのは「行列計算」というタイプの計算で,そのための「ライブラリ」がPythonの初期から作られ,利用されていました。このライブラリはそれからずっと開発が続けられていて,PythonがAIの世界を席巻する原動力になっています。最近では,日本の誇るスーパーコンピュータ「富岳」でも使えるように,改造手術が施されたりしています。
昔話をもう少しだけさせてください。過去を振り返って思うのは,Pythonの「太い幹」になっているのは「組み込み型」だ,ということです。数値,文字列,リストや辞書といった組み込み型にはPythonというプログラミング言語のエッセンスが詰まっています。最近のPythonは,ライブラリという沢山の美味しい実をぶら下げたとても枝振りの良い木に成長しました。でも,組み込み型が作った太い幹がなければ,こんなに沢山のライブラリを支えることはできなかったと思います。
コンピュータをもっと本格的に使いたい,プロの中のプロとしてプログラミングに取り組みたい人にとって「太い幹」となるものとして「コンピュータサイエンス」があります。コンピュータサイエンスは抽象化の度合いが高くてあまり一般向きではありません。Pythonの組み込み型は,程よく緩く,コンピュータを道具として使いこなすためのモデルとして,とてもよく機能するようにできていると感じます。

よりよいPythonの学び方

Pythonのプログラムを道具として使うことで解決される課題には,本当にいろいろな種類があります。AIや機械学習と一言で言っても,自然言語処理やディープラーニング,数値予測,大規模言語モデルなど細かな分野に分かれます。研究領域やビジネス,教育からアートまで,今日のPythonは,とても多くの分野をカバーしていて,それぞれの分野で課題解決に使われています。
このような「分野」のことを「ドメイン」と呼ぶことがあります。ドメインごとにライブラリがあり,ライブラリに備わっている数値モデルと計算モデルを作ってプログラムを作る,というのがPythonを使う時の道具立てです。あまり一般的な表現ではありませんが,この記事を読んでくれた人には通じるはずです。
ドメインで使われている数値モデルと計算モデルを深く理解するには,ドメイン特有の知識が必要になります。日付のモデルを理解するために,うるう年の知識が必要なのと同じです。でも,それぞれのモデルのモデルになっているのは「組み込み型」です。どんなドメインであっても,Pythonのライブラリである以上,組み込み型が元になって個別のモデルが作られる,という共通の構造を持っていることに変わりありません。
Pythonを学びたいなら,まず組み込み型についてよく学ぶべきです。シンプルでいいので,意味の分かるPythonのプログラムを読んで,できれば自分で書き換え,動かして結果を確認する,というサイクルをくり返すのはなかなか良い学習方法だと思います。「ただの写経」がしばしばプログラミング学習にとって意味がなくなってしまうのは,プログラムの文脈を理解しないまま書いてしまうからだと私は考えています。
Pythonそのものを学びたい人は多分稀な存在です。でもやはり,みんな組み込み型から始めるべきです。組み込み型をある程度マスターしたら,それぞれのドメインに進めばいいと思います。各ドメインの専用ライブラリは,たいていオブジェクト指向を使って書かれています。初めのうちはオブジェクト指向の設計的な要素については学ぶ必要はありません。最低限,オブジェクト指向で書かれたPythonのプログラムを読めれば,読む,動かす,書き換えるというサイクルを使って学び続けることができます。
そうして,Pythonの組み込み型にいったん慣れてしまい,しばらく経つと,不思議なことが起こります。
あるドメインの流行は,時間と共に過ぎ去ります。そして新しく流行する分野にも,Pythonのライブラリがたいてい存在しているのです。しかも新しいドメインは,これまで流行していたドメインから,少しだけズレた位置にあります。
過去に学んだ近いドメインの知識を使って,新しく流行し始めたドメインについて学ぶ事ができます。流行のドメインには,たいてい,というより必ずと言っていいほど,Pythonのライブラリが存在しています。ライブラリを使うに当たって必要な知識のうち,組み込み型についての知識は共通です。ドメイン固有で使われるデータ構造とアルゴリズムを学ぶだけで,ライブラリを使いこなすことができるようになります。
そうやってPythonを通じて新しいドメインについて学んで行くうちに,Pythonはあなたにとって欠くべからざる「道具」になるはずです。
Pythonは「ゆるく」学び始めることができるプログラミング言語です。そのままゆるく使い続けてもいいですし,より深く,特定ドメインに特化した学び方をしてもよいのです。だれにでも使い始められて,いつまでも道具として使い続けられる。それがPythonの持つ魅力なのかもしれません。

最後まで読んでくれてありがとう!


この記事が気に入ったらサポートをしてみませんか?