Data Type では,Pythonでよく使われるデータの種類について学びます.
最も基本的なデータタイプは, Bool Typeです.
これは,変数自体に True
や False
が入ります.
>>> x = True
という感じです.
また,命題についても,True
or False
に変換されて変数に入ります.
>>> y = (100 < 10)
>>> y
False
プログラムを書いていて,ある変数がどのようなデータタイプなのか, わからなくなることがあります.これ以降にも,様々なデータタイプが出てきますが,先にデータタイプの確認方法を学びましょう.
ある変数 x
がどのようなデータタイプかを調べるためには組込み関数 type()
を使います.
>>> type(x)
>>> bool
bool
Typeの変数には True
もしくは False
が割り当てられますが,
True
と False
にはそれぞれ, 1
と 0
という数字も割り当てられています
>>> x, y = True, False
>>> x + y
1
この,Bool TypeはListの要素にもなります.
Listは様々なオブジェクトを格納できる列のことです.
Listには,値や文字なども入れることができます.例えば,
>>> bools = [True, True, False, True]
という感じです.先ほどの, True
や False
に 1
と 0
が割り当てられることを考えると,
>>> sum(bools)
3
となります.この sum()
のような命令のことを関数と呼びます.
特に,この sum()
は組み込み関数とよばれ,pythonにもともと入っています.
ほかの組み込み関数については,公式の組み込み関数_ を参照してください.
PythonにはBool Type以外にのデータタイプも存在します.
例えば数字の, int
と float
の2つの種類のデータタイプがあります.
>>> a, b = 1, 2
>>> type(a)
int
``int`` がinterger Typeであり,
>>> c, d = 2.5, 10.0
>>> type(c)
float
となります.この int
と float
については後に詳しく説明します.
この,integerに関連する問題を一つ見てみましょう.
Python 2x では,2つのinteger(整数)同士の割り算では,integerの部分だけを返します.
n:
>>> 1/2
0
ただし, integer
と float
や, float
と float
同士の割り算では,少数以下も返されます.
>>> 1.0/2.0
0.5
ですし,
>>> 1.0/2
0.5
となります.
このような問題はPython 3xでは発生しません.しかし,この教科書はPyhton 2xを用いるので,読者はこのような問題に留意する必要があるでしょう.
複素数も,PythonにおけるPrimitiveなデータタイプの一つです.
Pythonでは,Complex Type と呼ばれます.
Pythonで複素数を表現するには,組み込み関数の complex()
を使います. complex(実部,虚部)
のように指定します.また,Pythonでは複素数は j
で表現されます.
>>> x = complex(1, 2)
>>> y = complex(2, 1)
とすれば,
>>> x*y
5j
となります.
Pythonには様々なコンテナが存在します. コンテナは,データーを集めておくために使われます.
例えば,先に説明した, list
は組み込みコンテナといって,Pythonにもともと備わっています.
listと同じような,組み込みコンテナとして tuple
(トゥープル,タプル)があります.
この, tuple
と list
の大きな違いの一つに, tupule
が immutable
であることが挙げられます.
tuple
が immutable
とは, tuple
の値が変更できないことを意味します.
一方で, list
は mutable
なので,値を変更することができます.
以下に例を示します,まず list
は mutable
すなわち持っている変数の数が増えたり,減ったり変わったりします.
>>> x = [1, 2]
という list
を考え,この1行目の,1を変化させてみましょう.
x[0]
というようにすると, list
であるxの0行目を指定できます.これを変更するには,>>> x[0]=10
というようにします.確認すると,
>>> x
[10, 2]
というように,変更されていることがわかります.
このように, list
は mutabl
です.しかし,一方で, tupule
は immutable
です.
>>> X = (1, 2)
X[0] = 10
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-531149b57146> in <module>()
----> 1 X[0] = 10
TypeError: 'tuple' object does not support item assignment
となってしまいます
mutable
な list
にも, immutable
なリストにも, unpacke
という操作を施すことができます.
unpacked
では,それぞれの行を指定した変数に当てはめることができます.
integers = (10, 20, 30)
x, y, z = integers
とすると
>>> x
10
>>> y
20
>>> z
30
というように割り当てられます.
また,slice notetion という操作も, mutable
, immutable
のどちらにも施すことができます.
例えば,
>>> a = [2, 4 , 6, 8]
という,listの1行目から,最後の行までを抜き出したいときは,
>>> a[1:]
[4, 6, 8]
と指定します.
また,ある行から,ある行までを抜き出したいとき,例えば,1-2行目を抜き出したいとき,
>>> a[1:3]
[4, 6]
というような指定の仕方をします.
list[抜き出しを開始する行番号:抜き出しを終わる行番号+1]
という感じです.
また,
>>> a[-2:]
[6, 8]
のように,最後の2行を抜き出すことができます.
以上の一連の操作は,文字列に対しても行えて,
>>> s = 'kobe univ.'
>>> s[-5:]
'univ.'
と抜き出せることができます.
このような,最後の数行を抜き出すという操作は,全体を確認するには長すぎるデータの内容を確認するときに,有効な場合があります.
先に, list
と tupule
という二種類の container
を紹介しました.
次に, set
と dictionary
という2つの container
について説明します.
まず, dictionary
は, list
と似ていますが,要素がkeyと言われる変数とヒモ付されている点が異なります.:
d = {'name': 'Frodo', 'age' : 33}
ここでは, 'name'
と 'age'
がkeyになっています.
こうすることで,作った dictionary
に対して,keyを指定することで,ヒモ付けされた情報を抜き出すことができます.
>>> d['age']
33
次に, set
というコンテナについて説明します.
set
はその名の通り, 集合の container
です.
>>> s1 = {'a', 'b'}
当然, type(s1)
は
>>> type(s1)
set
となります.
別の, s2
という set
を考えてみましょう.
>>> s2 = {'b', 'c'}
set
に対して,行える演算の一つに, issubset()
があります.
s1. issubset(s2)
としたとき, s1
が s2
の部分集合の場合,Trueを返し,そうでないとき,Falseと返します.
>>> s1. issubset(s2)
False
他にも, issubset()
は set
同士の共通部分を返します.
>>> s1. intersection(s2)
{'b'}
同じような,演算として,2つの集合の間の異なる要素を返す, difference()
があります.
>>> s1. difference(s2)
{'a'}
また, set
は重複する要素を持ちません.
>>> s3 = {'b', 'c', 'c', 'c'}
としても,
>>> s3
{'b', 'c'}
となります.
Pythonはその基本に,
- small core language
- extra functionality in separate libraries or modules
を持ちます.
例えば,平方根を計算する関数は,Pythonにはありません.(表現がアヤシイ)
この場合,moduleから関数を import
します.例えば, math
を import
してみましょう.
>>> import math
>>> math.sqrt(4)
2.0
となります.
他にも, numpy
(ナンパイ)にも同じような関数が入っていますが, nampy
は list
に対しても同じ計算を行える点が異なります.
>>> numpy.sqrt([1,4,16,64])
array([ 1., 2., 4., 8.])
試しに, math
で同じ計算をしてみると,
>>> math.sqrt([1,4,16,64])
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-2-50876051fb1b> in <module>()
----> 1 math.sqrt([1,4,16,64])
TypeError: a float is required
Pythonで分析を行う上で,テキストファイルを読み込んだり,作成したりする必要性が出てきます.
まずは, newfile.txt
というファイルを読み込んでみましょう.
(ここは飛ばしてる・・・・)
computingにおける,最も重要なtaskの一つに,繰り返しを用いた処理があります.
Pythonの強みの一つは,そのシンプルさと柔軟性にあります.
例えば,繰り返しの処理は for
と in
を使って,表現します.
その一例として, us_cities.txt
という都市とその人口のデータの処理をしてみましょう.
new york: 8244910
los angeles: 3819702
chicago: 2707120
houston: 2145146
philadelphia: 1536471
phoenix: 1469471
san antonio: 1359758
san diego: 1326179
dallas: 1223229
都市とその人口の間には, :
があるので,それを基準にして,都市名と人口を切り離します.
人口には,1000ごとに ,
で区切りましょう.
まずは,データを読み込みます.
us_cities.txt
を,同じディレクトリに置いて,
>>> data_file = open('us_cities.txt', 'r')
とします.次に,繰り返し処理を施し,
>>> for line in data_file :# data_fileの中で,line(行)ごとに処理を行う
>>> city, population = line.split(':') # Tupleをunpackする
>>> city = city.title()# 都市のの頭文字を大文字にする
>>> population = '{0:,}'.format(int(population))# 数字に','を入れる
>>> print(city.ljust(15) + population)
title()
は単語の先頭を大文字に,する組み込み関数です.
例えば,
>>> 'But cOme ye bAck wHen Summers in the meaDow.'.tilte()
'But Come Ye Back When Summers In The Meadow.'
となります.
気付いている人もいると思いますが,Pythonでは,ループ処理(looping)を行うとき index
を使わない方が好まれます.
例えば,
>>> for x in x_values:
print x*x
というコードのほうが,
>>> for i in range(len(x_values)):
>>> print x_values[i] 8 x_values[i]
というコードよりも良いことが,2つを比べてみればわかると思います.
Pythonでは,1つ目のコードのように,変数に対して i
のような index
を付けずにループ(looping)処理をシンプルにします.
その例の一つとして, zip()
という関数を説明しましょう. zip()
は2つの列の要素を対応させていく関数です.
>>> zip((1,2,3,4),("a","b","c"))
[(1, 'a'), (2, 'b'), (3, 'c')]
というように,この場合,2つの tuple
を要素ごとに組み合わせて, tuple
を作り, list
をつくります.
この関数を使って,県庁所在地を対応させるコードを書いてみましょう.(教科書では,国と首都を対応させるコードですが,ここで紹介するのもと同じものです)
まずは,2つのデータ, 都道府県のデータ;prefectures
, 県庁所在地のデータ;cities
を用意します.
>>> prefectures =('北海道(ほっかいどう)','青森県(あおもり)','岩手県(いわて)','宮城県(みやぎ)')
>>> cities = ('札幌(さっぽろ)','青森(あおもり)','盛岡(もりおか)','仙台(せんだい)')
次に,この2つを zip()
で対応させていきます.
>>> prefectures =('北海道(ほっかいどう)','青森県(あおもり)','岩手県(いわて)','宮城県(みやぎ)')
>>> cities = ('札幌(さっぽろ)','青森(あおもり)','盛岡(もりおか)','仙台(せんだい)')
>>> for prefecture, city in zip(prefectures, cities):
print '{0}の県庁所在地は,{1}です'.format(prefecture, city)
すると,出力は,
北海道(ほっかいどう)の県庁所在地は,札幌(さっぽろ)です
青森県(あおもり)の県庁所在地は,青森(あおもり)です
岩手県(いわて)の県庁所在地は,盛岡(もりおか)です
宮城県(みやぎ)の県庁所在地は,仙台(せんだい)です
'{0}の県庁所在地は,{1}です'
の {}
は zip()
で作った,対応を当てはめていく場所です. {0}
と書くと,そこに, zip(0, 1)
とした第0番目の要素が入ります. {0}
の中に,何も書かなかった場合は zip(0, 1)
の要素の順番通りに変数が当てはめられていきます.
例えば,
>>> print '{}の県庁所在地は,{}です'.format(prefecture, city)
としても,結果は変わらず,
北海道(ほっかいどう)の県庁所在地は,札幌(さっぽろ)です
青森県(あおもり)の県庁所在地は,青森(あおもり)です
岩手県(いわて)の県庁所在地は,盛岡(もりおか)です
宮城県(みやぎ)の県庁所在地は,仙台(せんだい)です
となります.
また.
>>> print '{1}の県庁所在地は,{0}です'.format(prefecture, city)
とすれば,:
札幌(さっぽろ)の県庁所在地は,北海道(ほっかいどう)です
青森(あおもり)の県庁所在地は,青森県(あおもり)です
盛岡(もりおか)の県庁所在地は,岩手県(いわて)です
仙台(せんだい)の県庁所在地は,宮城県(みやぎ)です
となり,都道府県と県庁所在地の順番が入れ替わります.
zip()``は ``dictionary
を作るのに便利です.
例えば,
>>> names = ['Tom', 'John']
>>> marks = ['E', 'F']
>>> dict(zip(names, marks))
{'John': 'F', 'Tom': 'E'}
というように,簡単にdictionary type のデータを作ることが出来ました.
index
がなくても,ループ処理ができるといっても,実際には index
が必要な時があります.
そのような場合は, enumerate()
を用いて, index
を割り当てていきましょう.
>>> prefecture_list=['北海道(ほっかいどう)','青森県(あおもり)','岩手県(いわて)','宮城県(みやぎ)']
>>> for index, prefecture in enumerate(prefecture_list):
>>> print '日本の東から{0}番目の都道府県は,{1}です'.format(index, prefecture)
とすれば,
日本の東から0番目の都道府県は,北海道(ほっかいどう)です
日本の東から1番目の都道府県は,青森県(あおもり)です
日本の東から2番目の都道府県は,岩手県(いわて)です
日本の東から3番目の都道府県は,宮城県(みやぎ)です
と出力されます.ここから, {0}
に index
が割り当てられていることがわかります.
ところで,この, enumerate()
では, index
の開始番号を指定することができましょう.
'日本の東から0番目の都道府県'
という日本語は,違和感があるので, enumerate(prefecture_list,1)
とすれば.
>>> for index, prefecture in enumerate(prefecture_list,1):
>>> print '日本の東から{0}番目の都道府県は,{1}です'.format(index, prefecture)
日本の東から1番目の都道府県は,北海道(ほっかいどう)です
日本の東から2番目の都道府県は,青森県(あおもり)です
日本の東から3番目の都道府県は,岩手県(いわて)です
日本の東から4番目の都道府県は,宮城県(みやぎ)です
というように出力されることから,indexが1から割り当てられていることがわかります.
Booolean values(True or False で評価されるvalues) として,処理されるものはたくさんあります.
ここでは,代表的なものを紹介します.
まずは,不等式.
>>> a,b,c,d,e,f = 1,1,2,3,5,8
>>> a<=b<c<d<e<f
True
等式は,Pythonでは, ==
で表現されます.
>>> x=1
>>> x==20
False
ノットイコール (neq) は, !=
で表現されます.
>>> 1!=20
True
if
を使うと,ある条件が満たされるかどうかで,場合分けすることができます.
>>> x= 'yes' if 5>2 else 'no'
x
'yes'
この条件式には,Pythonで認められているものであれば,どんなものでも許容されます.
if
のあとに,つねに成立するような命題をいれてみます.
>>> x= 'yes' if 42 else 'no'
>>> x
'yes'
常に満たされない,ものとして, if
のあとに空集合を入れてみましょう.
>>> x= 'yes' if [] else 'no'
>>> x
'no'
また, if
の後に 0
を入れても同じ結果になります.
つまり, 0
だけではなく, []
にも false
が割り当てられているということです.
bool()
を用いて,確認してみましょう.
>>>print(bool(0))
False
>>>print(bool(42))
True
>>>print(bool([]))
False
>>>print(bool([1,2,3]))
True
条件式は and
を用いて,複数の命題を組み合わせることもできます.
>>> 1<2 and 'あ' in 'あきら'
True
今まで紹介していないfunctionとして, max()
, min()
, ramge()
などがあります.
range()引数に指定した長さのlistを作ります.例えば,
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
となり,指定しない場合は0から始まるlistを作ります.
始めと終わりの数字を指定することもできます,
>>> range(-10,10)
[-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
次に, max()
は list
や tuple
といった引数の最大値を返す関数です.今までの,条件式や range()
を組み合わせて例を作ると
>>> max(range(100))>98
True
となります. range(100)
は0から99までの list
を作るので,
>>> max(range(100))>99
False
となることが分かります.
最後に, str()
は引数に指定した値の文字列を作ります.
>>> str(12)
'12'
関数(function)を書くことで,コードを明瞭に書くことができます.
なぜなら,
からです.
functionの定義の仕方を示しましょう.
引数の正負を調べる関数を定義します
def f(x):
if x < 0:
return 'nagetive'
return 'nonnegative'
とすれば,
>>> f(-5)
'nagetive'
lamba
を使うと,一行でfunctionを書くこともできます.
>>> f = lambda x: x**2
とすると,
>>> f(x=5)
25
のような関数を定義できます.
しかし,functionの内容を明確化するためにも, def
をつかったfunctionの定義を用いるほうが望ましいでしょう.
zip()
を使って内積を求める問題
適当な list
の内積を求める
>>> x=[1.0,1.0,2.0,3.0,5.0,8.0,13.0,21.0,34.0,55.0,89]
>>> y=[1,1,2,3,5,8,13,21.0,34.0,55.0,89.0]
この2つの list
の内積を求めてみよう
>>> S=0 #Sを0にしておく
>>> for a,b in zip(x,y): #zip()でx,yの要素をa,bに入れる
>>> S=S + a*b #for を使って各要素を足しあわせていく
>>> print(S) #Sの値を出す
12816.0
問題では zip()
を用いましたが,一行で書くこともできます.
sum()
の中に条件式を入れることもできるので
>>> sum(a*b for a,b in zip(x,y))
12816.0
とかける.
一行で0から99の偶数の数を計算する.
ちなみに,
>>> x%2
という操作が,xを2で割った余りを返すことがヒントです.
まず,コードの内容を把握するために,複数行で書いてみる.
>>> s=0
>>> for x in range(100):
>>> if x%2==0:
>>> s=s+1
>>> print(s)
50
これを,一行にまとめる.
Exercise1 Par1のように sum()
を用いて表現する.
range(100)
のなかで, x%2==0
が true
の回数を数えればいいので,
>>> sum(1 for x in range(100) if x%2==0)
50
xが偶数の時に x%2
が0になることを利用する方法もある.
0にはFalseが割り当てられるので,xが偶数なら not x%2
は true
になる.
true
には1が割り当てられているので,
>>> sum(not x%2 for x in range(100))
50
pairs = ((2, 5), (4, 2), (9, 8), (12, 10))
というリストの tuple
の(a,b)のうち,a,bのどちらもが偶数の tuple
の数を数える.
(a,b)のa,bに関してそれぞれ条件式をかくので,(a,b)を分ける必要がある.
それは,
>>> for a,b in pairs
とすればよい.あとは条件式をかいてそれが満たされる回数を数えれば良いので,
>>> pairs=((2,5),(4,2),(9,8),(12,10))
>>> n = 0
>>> for a,b in pairs:
>>> if a%2==0 and b%2==0:
>>> n=n+1
>>> print(n)
2
とすれば良い.
これも,一行でかけて,
>>> sum(1 for a,b in pairs if a % 2==0 and b%2==0 )
2
となる.
Polynominal(多項)の式を計算する関数を作るExersise.
式は以下の通り,
所与の数列 \(a_nとx^n\) の掛け算を足し合わせてできる関数p(x)を作れば良い.
数列が所与といっても,それはPolynominal(多項)の式自体がそうなのであって,計算するにはその具体的な値が必要です.なので,関数の引数としては,xの値と,数列anを list
として指定します.
数列のnとxの乗数が共通しているのでそれを利用して書いてみましょう.一番,思いつきやすいのは,項をterとおいて,足しあわせていき,足し合わせるごとのnを1増やしていく方法だと思います.
>>> def p(x, coeff):
>>> n, ter = 0, 0
>>> for a in coeff:
>>> ter = ter + (a * (x**n))
>>> n += 1
>>> return ter
しかし,先に習ったように, enumerate()
を用いれば, index
をわざわざ作る必要はありません.
>>> def p2(x, coeff):
>>> ter = 0
>>> for n,a in enumerate(coeff):
>>> ter = ter + (a * (x**n))
>>> return ter
もう少し工夫すれば,この関数を2行で書くこともできます.
>>> def p3(x, coeff):
>>> return sum(a*(x**n) for n,a in enumerate(coeff))
英文の文字列の中の大文字の数を数える関数を作る問題です.
ヒントとして,文字列を大文字にして返す関数, .upper()
が与えられているので,これを上手く使いましょう.
関数の流れとしては,文字列, strings
の中の文字xを一文字づつ取り出して,その文字の大文字を .upper()
で作ります.
そして,それが取り出したxと同じかどうかを調べ,同じだった回数を数えればよいでしょう.
>>> def f(string):
>>> n=0
>>> for x in string:
>>> if x == x.upper() and x.isalpha():
>>> n=n+1
>>> return n
ただし,この関数の定義をみればわかるように, x.isalpha()
というmethodが用いられています.
これは,文字が英字であるかどうかを調べるmethodです.
もし,これがないと,スペースやピリオドといった,英字でないものに対してもTrueを返してしまい,正確にstringsの中の大文字の数を数えることはできません.
しかし,このような教科書に出ていないmethodを使わなくても,工夫して同じ関数を定義することができます.
>>> upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> 'A' in upper
True
このように,あらかじめ,大文字の英字を文字列として与えてこのなかのどれかと,stringの文字が同じだった時,Trueを返すようにすればよいのです.
また,Trueの値が1であるということを思い出せば,直接Trueを合計すればいいことにも気づくでしょう.
>>> def count_upper(s):
>>> upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> return sum(c in upper for c in s)
2つの流列(sequence)a,b,が与えられていて,aの要素すべてが,bの要素に含まれていたらTrueを返す関数をつくる問題.
ここでいう,流列とはlistやtuple,stringを意味する.
また,setsやset methodを使わずに関数を定義するように指示されています.
seq_aの要素を1つずつ取り出して,それが,seq_bの中に入っていなければFalse,それ以外ならばTrueをかえす関数を書いてみましょう.
>>> def f(seq_a,seq_b):
>>> for a in seq_a:
>>> if a not in seq_b:
>>> return False
>>> return True
この関数の問題点は,seq_aの要素全てに対して,それがseq_bに属しているかを調べている点です.
問題文では,“の要素すべてが,bの要素に含まれていたらTrue”とあるので,seq_aなかで,一つでもseq_bに入っていないものを見つけたら,すぐにFalseになる関数を書けば,より効率的な関数を書くことができます.
そのような,関数を定義するために,all()という組み込み関数を用います.
all()は,iterable の全ての要素が真ならば (もしくは iterable が空ならば) True を返すので,bにないものが見つかった時点で,動作をやめます.
つまり,seq_aの要素全てに対して,それがseq_bに属しているかを調べている最初の解答例よりも早く処理が終わります.
>>> def f(seq_a,seq_b):
>>> return all(a in seq_b for a in seq_a)