>
図書館情報技術論
>
3
Python を用いた貸出統計の作成
1. リスト
- 変数に設定することができるものには、「リスト」と呼ばれるものもある。
- 「リスト」とは、複数の文字や数値のデータが並んだものである。
- 変数に入れるときには、全体を角かっこ「[ ]」で囲み、中のデータはコンマで区切る。
サンプルファイル「py301.ipynb」
- 以下のように、変数「bungakusho」に、5人の人名が入力されている。
# -*- coding: utf-8 -*-
bungakusho=["芥川龍之介","直木三十五","太宰治","三島由紀夫","江戸川乱歩"]
print(bungakusho)
print(bungakusho[0])
['芥川龍之介', '直木三十五', '太宰治', '三島由紀夫', '江戸川乱歩']
芥川龍之介
- 実行結果の上の行は、リストの全体を print したものである。
- 角かっこで囲まれ、コンマで区切られていることに注意。
- なお、文字の前後の引用符が「'」となっているが、これは「"」と意味は同じで、どちらも単に「データが文字である」ことを意味している。
- 引用符自体はデータではないので、注意。
- プログラムの最後の行、 print(bungakusho[0]) の [0] は、「リストの0番目のデータ」という意味。
- このように、リストの要素の順序を示す数字のことを「インデックス」と呼ぶ。
- Python では、順序を数えるときは常に「0番目」から数えるので、 [0] は通常の1番目、 [1] は通常の2番目となることに注意。
- したがって、最後のインデックスは、「リストの要素数-1」となる。
- ここで、print(bungakusho[0]) の角かっこの中のインデックスの数字を [1] から [5] まで順に書き換えて、実行してみること。
- そうすると、 [4] までは正常に表示されるが、 [5] と入れるとエラーが出てしまう。
IndexError Traceback (most recent call last)
~\***\***\***/***/***.py in
3 bungakusho=["芥川龍之介","直木三十五","太宰治","三島由紀夫","江戸川乱歩"]
4 print(bungakusho)
----> 5 print(bungakusho[5])
IndexError: list index out of range
- このエラーは「リストの5番目は範囲外」だというエラーである。
- つまり、データが存在しないことを警告している。
- 数字を [0] から [4] の範囲に戻せば、エラーは出なくなる。
- たとえば、 [2] にすれば、以下のように表示される。
['芥川龍之介', '直木三十五', '太宰治', '三島由紀夫', '江戸川乱歩']
太宰治
- リストに含まれている特定のインデックスのデータを、個別に書き直すこともできる。
- 入力方法は、以下のとおり。
変数[インデックス] = 新しいデータ
- ここで、インデックス [2] の「太宰治」を、「川端康成」に書き換えてみる。
- 追加する場所は、bungakusho=["芥川龍之介","直木三十五","太宰治","三島由紀夫","江戸川乱歩"] のすぐ下とする。
- ここを改行して1行追加し、次のようにしてみる。
bungakusho=["芥川龍之介","直木三十五","太宰治","三島由紀夫","江戸川乱歩"]
bungakusho[2]="川端康成"
print(bungakusho)
print(bungakusho[2])
- この状態で実行すると、以下のように表示される。
- インデックス [2] (実質は3番目) のデータが書き換えられていることが分かる。
['芥川龍之介', '直木三十五', '川端康成', '三島由紀夫', '江戸川乱歩']
川端康成
- リストの内容は、追加や削除も可能だが、多少複雑になるので、ここでは扱わない。
2. 辞書
- 変数に設定することができるものには、「辞書」と呼ばれるものもある。
- 「辞書」とは、「キー」と「値」のペアでデータが登録されているものである。
- 変数に入れるときには、全体を波かっこ「{ }」で囲み、「キー」と「値」の間はコロンで区切る。
- データのペアが複数ある場合は、コンマで区切る。
- 辞書に登録されたデータは、「キー」を指定して呼び出すことができる。
サンプルファイル「py302.ipynb」
# -*- coding: utf-8 -*-
kenji={"shimei":"宮沢賢治","yomi":"ミヤザワ・ケンジ","seinen":1896,"botsunen":1993}
print(kenji)
print(kenji["shimei"])
{'shimei': '宮沢賢治', 'yomi': 'ミヤザワ・ケンジ', 'seinen': 1896, 'botsunen': 1993}
宮沢賢治
- 実行結果の上の行は、辞書の全体を print したものである。
- 波かっこで囲まれ、コロンとコンマで区切られていることに注意。
- プログラムの最後の行、 print(kenji["shimei"]) の ["shimei"] は、「キーが "shimei" のデータ」という意味。
- リストでインデックスを指定した場合のように、角かっこでキーを指定すれば、対応するデータが表示される。
- ここで、print(kenji["shimei"]) の角かっこの中を ["yomi"] ["seinen"] ["botsunen"] に書き換えて、実行してみること。
- 辞書では、キーのないものを指定した場合はエラーとなる。
- 最後の行で、わざと存在しないキー ["aaaa"] を指定してみると、以下のエラーが表示される。
KeyError Traceback (most recent call last)
~\***\***\***/***/***.py in
3 kenji={"shimei":"宮沢賢治","yomi":"ミヤザワ・ケンジ","seinen":1896,"botsunen":1993}
4 print(kenji)
----> 5 print(kenji["aaaa"])
KeyError: 'aaaa'
- 辞書に含まれている特定のキーのデータを、個別に書き直すこともできる。
- 入力方法は、以下のとおり。
変数[キー] = 新しいデータ
- ここで、キーが ["botsunen"] のデータ「1993」は誤りだったので、この値を「1933」に書き換えてみる。
- 追加する場所は、kenji={"shimei":"宮沢賢治","yomi":"ミヤザワ・ケンジ","seinen":1896,"botsunen":1993} のすぐ下とする。
- ここを改行して1行追加し、次のようにしてみる。
- また、最後の行のキーも ["botsunen"] に直しておき、正しく表示されるかどうか確認してみる。
kenji={"shimei":"宮沢賢治","yomi":"ミヤザワ・ケンジ","seinen":1896,"botsunen":1993}
kenji["botsunen"]=1933
print(kenji)
print(kenji["botsunen"])
- この状態で実行すると、以下のように表示される。
- キーが ["botsunen"] のデータが書き換えられていることが分かる。
{'shimei': '宮沢賢治', 'yomi': 'ミヤザワ・ケンジ', 'seinen': 1896, 'botsunen': 1933}
1933
- 辞書の内容は、追加や削除も可能だが、多少複雑になるので、ここでは扱わない。
3. 条件分岐
- 条件分岐とは、ある条件を満たしているかどうかを判断し、その結果によってその後の処理を異なるものにするためのものである。
- Python では、「if」と、「else」を用いる。
サンプルファイル「py303.ipynb」
- このサンプルでは tokuten が 80 以上かどうかを判断し、条件を満たしている場合は「合格」、満たしていない場合は「不合格」と表示することを目的としている。
- プログラム全体は、以下のように入力されている。
# -*- coding: utf-8 -*-
tokuten = 100
print("合格判定プログラム開始")
print("今回の得点",tokuten)
if tokuten >= 80:
print("合格")
else:
print("不合格")
print("合格判定プログラム終了")
合格判定プログラム開始
今回の得点 100
合格
合格判定プログラム終了
- このプログラムでは、条件が次のように設定されている。
「if」で始まる行に、満たすべき条件が記載されている。
「if」の行の最後には、コロンを付ける。コロンまでが条件とみなされる。
ここでの条件は「tokuten >= 80」である。
これは、「数値が80以上」を意味している。
- 条件を満たしている場合の処理は、行を変えて、字下げして入力する。
- 字下げの文字数は、1文字以上であればいくらでもよいが、4文字分が標準的。
- 処理が複数ある場合は、同様に改行して字下げをして入力すればよい。
- このサンプルでは、80点以上の場合は「合格」と表示される。
- 条件を満たしていない場合の処理を入力する場合には、まず、行を変えて、今度は字下げをしないで「else:」と入力する。
- 「else:」の最後にも、コロンが必要なので注意。
- 次に、「else:」の下に、行を変えて、字下げして処理を入力する。
- このサンプルでは、80点以上でない場合は「不合格」と表示される。
- 条件分岐が終了した後の処理は、字下げせずに入力する。
- このサンプルでは、条件を満たしているかどうかにかかわらず、最後に「合格判定プログラム終了」と表示される。
- ここで、最初の行の tokuten の 100 を 79 に書き換えて、実行してみると、以下のように表示される。
- 今度は「不合格」と表示されることと、それ以外の表示は変化しないことに注意。
合格判定プログラム開始
今回の得点 79
不合格
合格判定プログラム終了
4. 繰り返し
- 繰り返しには「for」を使う。
- 条件の設定方法として、リストを用いる方法や、range()を用いる方法など、いくつかの方法がある。
- 基本的な条件設定方法は、以下のとおり。
for 「1回ごとの値が入る変数」 in 「対象となるリストや range()」 :
- 「for」の行も、最後にコロンが必要なので注意。
- その下に改行し、字下げして、繰り返しが続行している間の処理を入力する。
- 設定した条件を満たしている間は、字下げで設定した処理を繰り返す。
- 条件を満たさなくなった時点で処理をストップして、次に進む。
サンプルファイル「py304.ipynb」
- このサンプルでは、3種類の方法で、繰り返しの処理を実行している。
- なお、この3種類には、まったく関係がなく、独立して処理される。
- プログラム全体は、以下のように入力されている。
# -*- coding: utf-8 -*-
a = [1,2,3,4]
print("リスト a による表示開始")
for i in a:
print("変数 i の値",i)
print("リスト a による表示終了")
print("------------------------")
b = ['芥川龍之介', '直木三十五', '太宰治', '三島由紀夫', '江戸川乱歩']
print("リスト b による表示開始")
for j in b:
print("変数 j の値",j)
print("リスト b による表示終了")
print("------------------------")
print("range()による表示開始")
for k in range(4):
print("変数 k の値",k)
print("range()による表示終了")
リスト a による表示開始
変数 i の値 1
変数 i の値 2
変数 i の値 3
変数 i の値 4
リスト a による表示終了
------------------------
リスト b による表示開始
変数 j の値 芥川龍之介
変数 j の値 直木三十五
変数 j の値 太宰治
変数 j の値 三島由紀夫
変数 j の値 江戸川乱歩
リスト b による表示終了
------------------------
range()による表示開始
変数 k の値 0
変数 k の値 1
変数 k の値 2
変数 k の値 3
range()による表示終了
- 最初の例は、リストに数値が4個あるので、処理を4回繰り返している。
- 次の例は、リストに文字が5個あるので、処理を5回繰り返している。
- 最後の例は、range() で 4 を指定しているので、処理を4回繰り返している。
- range() による繰り返しの場合に、最初の値が「0」であることに注意。
- このことから、range(4) の実行結果は、リスト [0,1,2,3] の実行結果と等しいことが分かる。
5. メソッドとスライス記法について
- 次のサンプルファイルの中では、「メソッド」と「スライス記法」が使われている。
- このため、この2つについて、ここで簡単に触れておく。
メソッド
- データに結びついた関数のことをメソッドと呼ぶ。
- メソッドを用いることにより、データをさまざまに操作することができる。
- メソッドは、次のように呼び出す。
データ.メソッド名(引数)
- たとえば、ある文字列を分割する場合には、「.split()」というメソッドを使う。
- 以下の例では、文字列 "2012/04/01,A,007" を、コンマの位置で3つの文字列に分割し、リストの形式のデータとする。
"2012/04/01,A,007".split(",")
↓
単独の文字列「"2012/04/01,A,007"」が、以下のように、3つの文字列に分割される。
↓
"2012/04/01"
"A"
"007"
↓
分割と同時に、以下のようなリストの形式のデータとなる。
↓
["2012/04/01","A","007"]
- 上記の例で、.split(",") のカッコの中の "," は、分割する位置が「コンマ」であることを表している。
- このカッコの中を任意に設定することによって、任意の位置で分割することができる。
- メソッドは、「.split()」以外にも多くの種類がある。
- ここではすべてのメソッドを説明することはできないが、サンプルファイルで使用するものを2種類挙げてみる。
- 例1: 辞書のキー部分だけを抜き出してリストの形式のデータにするメソッド
.keys()
- 例2: リストの形式のデータを順番に並べるメソッド
.sort()
スライス記法
- ある文字列から部分的に文字列を取り出すときの書き方を、スライス記法と呼ぶ。
- 角カッコとコロン記号を使い、以下のような形で指定する。
文字列 [ 取り出し開始文字の位置 : 取り出し終了文字の位置 ]
- スライス記法では、先頭の文字の位置が「0文字目」となる。
- また、取り出し終了文字の位置の数値は、取り出し開始文字の位置の数値に、取り出す文字数を加算したものになることに注意。
- このルールは少し分かりにくいので、以下の図のように、文字の間の「切れ目」に番号を付け、その「切れ目」にハサミを入れて文字列を切り出しているとイメージするとよい。
- たとえば、文字列 "2012/04/01,A,007" の先頭から4文字を表すには、以下のように、0 から 4 までを指定する。
"2012/04/01,A,007"[0:4]
- また、スライス記法の特殊な形として、[:-1] などという表現も用いられる。
- これは、以下の2つの特殊な用法を組み合わせたものである。
- 取り出し開始位置が「0文字目」のときは、「0」を省略できる。
- マイナスの数字を指定すると、「文字列の末尾から何文字目」の意味となる。
- したがって、[:-1] は「0文字目から、最終文字の1文字手前まで」を意味する。
- (別の言い方をすれば、「その文字列の、末尾の1文字を削除したもの」と同じ。)
サンプルファイル「py305.ipynb」
# -*- coding: utf-8 -*-
print("2012/04/01,A,007")
print("2012/04/01,A,007".split(","))
print("2012/04/01,A,007"[0:4])
print("2012/04/01,A,007"[:-1])
- このプログラムを実行すると、以下のように表示される。
2012/04/01,A,007
['2012/04/01', 'A', '007']
2012
2012/04/01,A,00
- 分割位置やデータを書き換えてみて、結果がどうなるか試してみること。
6. 貸出統計の計算例
- ここでは、図書館の貸出記録を想定した架空のデータをもとにして、2種類の貸出冊数の統計を計算してみる。
(データ出典: 山本哲也著. 図書館員のためのプログラミング講座. 日本図書館協会, 2013.)
- この架空のデータのファイル名は「bjournal.txt」であり、データの項目は「貸出日」「端末」「資料分類」の3種類を想定している。
- 以下は、最初の3件のデータの例。
2012/04/01,C,330
2012/04/01,C,835
2012/04/01,B,319
- このファイルを使い、月別の合計を計算するプログラムと、分類別の合計を計算するプログラムを作成してみる。
- なお、もとのデータファイルは同一なので、ファイルをオープンして読み込む部分はどちらも同じになる。
月別の計算例
サンプルファイル「py306.ipynb」
# -*- coding: utf-8 -*-
# 月ごとの貸出冊数を集計する
mfreq = {}
f = open('bjournal.txt', encoding="utf-8")
for line in f:
d = line[:-1].split(",")
k = d[0][0:7]
# 集計用辞書にキーがなければ,初期値の0を入れておく
if k not in mfreq:
mfreq[k] = 0
# ひとつずつ集計
mfreq[k] += 1
# レポート表示
ks = list(mfreq.keys())
ks.sort()
for k in ks:
print("%s の貸し出し冊数: %d" % (k, mfreq[k]))
- このプログラムでは、以下のような変数を用いている。
- mfreq は辞書形式のデータで、辞書のキーは年月、キーに対応する値は貸出冊数。
- f は、ファイル「bjournal.txt」。
- line は、ファイルから1行ずつ読み込んだ文字列。
- d は、line[:-1] をコンマで分割 (.split) してリストの形式のデータにしたもの。
- k は、d の0番目のデータの、0文字目から7文字目を取り出したもの。
- ks は、mfreq の辞書のキーを抜き出してリストの形式のデータにしたもの。
- 最後の print の中の「%s」と「%d」は特殊な使い方で、「%s」には文字列のデータが、「%d」には数値のデータが流し込まれる。
- 中央付近に置かれた単独の「%」は、その左側のデータと、その右側のデータとを分離する記号である。
- このプログラムでは、左側にある「%s」と「%d」に、右側にある「k」の値と「mfreq[k]」の値が、それぞれ流し込まれる。
- このように、「%s」や「%d」を使うと、ある変数の前後に任意の文字列を設定することができるので、便利である。
- これを実行すると、以下のように表示される。
2012/04 の貸し出し冊数: 484
2012/05 の貸し出し冊数: 462
2012/06 の貸し出し冊数: 290
2012/07 の貸し出し冊数: 311
2012/08 の貸し出し冊数: 415
2012/09 の貸し出し冊数: 295
2012/10 の貸し出し冊数: 299
2012/11 の貸し出し冊数: 319
2012/12 の貸し出し冊数: 286
2013/01 の貸し出し冊数: 290
2013/02 の貸し出し冊数: 191
2013/03 の貸し出し冊数: 449
分類別の計算例
サンプルファイル「py307.ipynb」
# -*- coding: utf-8 -*-
# 分類ごとの貸出冊数を集計する
cfreq = {}
f = open('bjournal.txt', encoding="utf-8")
for line in f:
d = line[:-1].split(",")
# 分類の類目だけを取り出す
k = d[2][:1]
# 集計用辞書にキーがなければ,初期値の0を入れておく
if k not in cfreq:
cfreq[k] = 0
# ひとつずつ集計
cfreq[k] += 1
# レポート表示
ks = list(cfreq.keys())
ks.sort()
for k in ks:
print("分類 %s の貸し出し冊数: %d" % (k, cfreq[k]))
- このプログラムでは、以下のような変数を用いている。
- cfreq は辞書形式のデータで、辞書のキーは分類記号の1桁目、キーに対応する値は貸出冊数。
- f は、ファイル「bjournal.txt」。
- line は、ファイルから1行ずつ読み込んだ文字列。
- d は、line[:-1] をコンマで分割 (.split) してリストの形式のデータにしたもの。
- k は、d の2番目のデータの、0文字目から1文字目を取り出したもの。
- ks は、cfreq の辞書のキーを抜き出してリストの形式のデータにしたもの。
- 「py306.ipynb」と同様に、最後の print の中の「%s」と「%d」は特殊な使い方で、「%s」には文字列のデータが、「%d」には数値のデータが流し込まれる。
- 中央付近に置かれた単独の「%」は、その左側のデータと、その右側のデータとを分離する記号である。
- このプログラムでは、左側にある「%s」と「%d」に、右側にある「k」の値と「cfreq[k]」の値が、それぞれ流し込まれる。
- これを実行すると、以下のように表示される。
分類 0 の貸し出し冊数: 195
分類 1 の貸し出し冊数: 295
分類 2 の貸し出し冊数: 568
分類 3 の貸し出し冊数: 777
分類 4 の貸し出し冊数: 187
分類 5 の貸し出し冊数: 252
分類 6 の貸し出し冊数: 120
分類 7 の貸し出し冊数: 186
分類 8 の貸し出し冊数: 312
分類 9 の貸し出し冊数: 546
分類 A の貸し出し冊数: 106
分類 S の貸し出し冊数: 315
分類 X の貸し出し冊数: 232
クイズ
- 「py307.ipynb」を使い、以下のパターンで表示させたいとする。
- どこを、どのように修正すればよいか?
195 は、分類 0 の貸し出し冊数です。
295 は、分類 1 の貸し出し冊数です。
568 は、分類 2 の貸し出し冊数です。
777 は、分類 3 の貸し出し冊数です。
187 は、分類 4 の貸し出し冊数です。
252 は、分類 5 の貸し出し冊数です。
120 は、分類 6 の貸し出し冊数です。
186 は、分類 7 の貸し出し冊数です。
312 は、分類 8 の貸し出し冊数です。
546 は、分類 9 の貸し出し冊数です。
106 は、分類 A の貸し出し冊数です。
315 は、分類 S の貸し出し冊数です。
232 は、分類 X の貸し出し冊数です。
今回のサンプルファイルについて
- 以下は、今回の授業で配付するサンプルファイル。
- ただし、授業の際は、これらのファイルを先生用パソコンからファイル転送するので、以下のリンクは使用しない。
- 欠席した場合や、授業終了後の復習などの場合に、適当な場所へダウンロードして使用すること。