初心者のためのpython入門

自分がつまづいたところやつまづきやすいところを中心に書いていきます。また、役に立つライブラリの紹介などをしていきます。

リスト内包表記

前書き

今回は、リスト内包表記について説明します。リスト内包表記をマスターすれば、コードがスッキリします。

内包表記の説明と種類

内包表記はあるイテラブルオブジェクトを利用して、別のイテラブルオブジェクトを作成するための記法のことです。内包表記には、リスト内包表記・辞書内包表記・セット内包表記があります。特に、リスト内包表記は頻出です。

リスト内包表記

リスト内包表記の基本構文は、次のようになります。

リスト内包表記は、

  1. イテレータから1つずつ要素を取り出す
  2. 変数に代入する
  3. 式で評価
  4. リストに加える

という一連の流れを繰り返します。 この流れは、for文と同じです。

# sample.py
l1 = []
for i in range(10):
    l1.append(i)
print(l1)

l2 = [i for i in range(10)] # iという変数に要素を代入している
print(l2)

l3 = [i*2 for i in range(10)] # 全ての要素を2倍している
print(l3)
# 実行結果
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

実行結果は、上記のようになります。リスト内包表記により簡単に数字の配列を作成できることがわかります。このように、リスト内包表記を用いれば大概のfor文を置き換えることができます。式と書かれているところで何かしらの計算をすることもできます。

if文を含むリスト内包表記

if文を含むリスト内包表記の基本構文は、次のようになります。

if文を含むリスト内包表記は、

  1. イテレータから1つずつ要素を取り出す
  2. 変数に代入する
  3. 条件判定⇨真:4番・偽:1番
  4. 式で評価
  5. リストに加える

という一連の流れを繰り返します。

#sample.py
l1 = []
for i in range(10):
    if i % 2 == 0:
        l1.append(i)
print(l1)

l2 = [i for i in range(10) if i % 2 == 0]
print(l2)

l3 = [i*2 for i in range(10) if i % 2 == 0]
print(l3)
[0, 2, 4, 6, 8]
[0, 2, 4, 6, 8]
[0, 4, 8, 12, 16]

実行結果は、上記のようになります。条件判定されて、期待通りの結果になっていることがわかります。

if~elseを含むリスト内包表記

if~else文を含むリスト内包表記の基本構文は、次のようになります。

if~elseの場合は、ifのみの場合と場所が違うので気をつけてください。 if~else文を含むリスト内包表記は、

  1. イテレータから1つずつ要素を取り出す
  2. 変数に代入する
  3. 条件判定⇨真:式A・偽:式Bで評価
  4. リストに加える

という一連の流れを繰り返します。

# sample.py
l1 = []
for i in range(10):
    if i % 2 == 0:
        l1.append(i)
    else:
        l1.append(i+1)
print(l1)

l2 = [i if i % 2 == 0 else i+1 for i in range(10)]
print(l2)

l3 = [i*2 if i % 2 == 0 else (i+1)*2 for i in range(10)]
print(l3)
# 実行結果
[0, 2, 2, 4, 4, 6, 6, 8, 8, 10]
[0, 2, 2, 4, 4, 6, 6, 8, 8, 10]
[0, 4, 4, 8, 8, 12, 12, 16, 16, 20]

実行結果は上記のようになります。全ての要素を偶数にすることができました。

様々なリスト内包表記

今回紹介したものを組み合わせることによりできる、様々なリスト内包表記の例をサンプルとして挙げておきます。

# sample.py
# 2次元リストの作成
l1 = []
l2 = []
for i in range(3):
    l2 = []
    for j in range(3):
        l2.append(j)
    l1.append(l2)  
print(l1)

l3 = [[i for i in range(3)] for _ in range(3)] # 使わない要素には_を使うことが多い
print(l3)
# 実行結果
[0, 1, 2], [0, 1, 2], [0, 1, 2]]
[[0, 1, 2], [0, 1, 2], [0, 1, 2]]
# sample.py
# 複数の条件(要素が正なら1、負なら-1、ゼロなら0)による演算
l = [1, -2, 0, -3, 3, 5, 0, -2] 

l1 = []
for i in l:
    if i > 0:
        l1.append(1)
    elif i < 0:
        l1.append(-1)
    else:
        l1.append(0)
print(l1)

l2 = [1 if i > 0 else -1 if i < 0 else 0 for i in l] 
print(l2)
# 実行結果
[1, -1, 0, -1, 1, 1, 0, -1]
[1, -1, 0, -1, 1, 1, 0, -1]

このようにリスト内包表記で様々なことができます。
しかし、複雑になりすぎるリスト内包表記は使わない方が良いでしょう。

あとがき

お疲れさまでした。辞書内包表記とセット内包表記は次回説明します。基本的にはリスト内包表記と同じです。

pandas~ファイル編~

前書き

久しぶりの更新となりました。今回は、ファイル操作について説明します。

csvファイルで保存

pandasは、to_csv()を使うことにより、DataFrame型やSeries型をcsvファイルとして保存できます。

  • pd.to_csv(file): file引数には、保存したい場所へのパスとファイル名を与えます。
# to_csv.py
import pandas as pd

df = pd.DataFrame([['一', '二', '三'], ['one', 'two', 'three'], ['eins', 'zwei', 'drei']], index=['日本語', '英語', 'ドイツ語'], columns=[1, 2, 3])

print(df)

df.to_csv('number.csv') # 同じディレクトリにnumber.csvファイルが作成される
# 実行結果
     1     2      3
日本語      一     二      三
英語     one   two  three
ドイツ語  eins  zwei   drei

f:id:tiginkgo:20180521205418p:plain
ターミナルでの実行結果(lsはディレクトリに存在するファイルとディレクトリを確認するコマンド)

上記の実行結果より、csvファイルとしてデータが保存できたことがわかります。

to_csvのオプション

to_csvには、様々な引数があります。ここでは、よく使うものを紹介します。

引数 説明
index インデックスを保存するかを真偽値で指定。デフォルトはTrue。
header 列名を保存するかを真偽値で指定。デフォルトはTrue。

csvファイルの読み込み

pandasでcsvファイルを読み込むには、read_csv()を使います。

  • pd.read_csv(file): file引数には、読み込みたいcsvファイルまでのパスを与えます。返り値は、DataFrame型です。
# read_csv.py
import pandas as pd

df_1 = pd.read_csv('number.csv') 
print(df_1)

df_2 = pd.read_csv('number.csv', index_col=0, header=0) # index_colとheaderを指定
print(df_2) 
# 実行結果
# print(df_1)
  Unnamed: 0     1     2      3
0        日本語     一     二      三
1         英語   one   two  three
2       ドイツ語  eins  zwei   drei

# print(df_2)
         1     2      3
日本語      一     二      三
英語     one   two  three
ドイツ語  eins  zwei   drei

また、他のcsvファイルを試したい場合は気象庁などからダウンロードして確認してみてください。

read_csvのオプション

read_csvは、様々な引数があります。ここでは、よく使うものを紹介します。

引数 説明
sep 各行をフィールドに分割するのに用いる文字列や正規表現csvファイルなら必要ありません。例えば、tsvファイルなら'\t'を指定します。
header 列名として使う行の番号。デフォルトは0。ヘッダがない場合はNoneを指定。
index_col インデックスとして使う列の番号。デフォルトはNone
skiprows ファイルの先頭から無視する行数。デフォルトは0。
nrows ファイルの先頭で読み込む行数。
encoding Unicodeとして用いる文字コード。デフォルトは'utf-8'。

引数の補足説明をします。
例えば、skiprows=10・nrows=10とした場合は、先頭から10行飛ばしたところから10行分読み込まれます。 また、日本のサイトが提供するcsvファイルは、shift-jis形式が多いのでencodingを指定する必要があるかもしれません。上記の気象庁のサイトでは、encoding='shift-jis'と指定する必要があります。

あとがき

お疲れ様でした。これで pandasについての説明は、簡単にですが一通り終わりです。次回は、内包表記について説明します。

pandas~欠損値編~

まえがき

今回は、欠損値の処理について説明します。欠損値の処理は、最近流行りの機械学習においても非常に重要です。

pandasにおける欠損値

pandasにおける欠損値は型に依らず全てNaN(Not a Number)で表現されます。
また、Pythonの組み込み値であるNoneも欠損値として扱われます。

欠損値の確認

欠損値の確認は、isnull()notnull()を使います。

  • isnull(): 欠損値があるかどうかを示す真偽値を持ったオブジェクトを返す(欠損値がTrue)
  • notnull(): isnull()と反対の動作
import pandas as pd
import numpy as np

sr = pd.Series([1, 2, 3, np.nan, 8])
print(sr.isnull())
print(sr.notnull())

df = pd.DataFrame([[1., 2., 2.5, 4.5],
                   [1., np.nan, np.nan, 5.],
                   [2., 3., 3.5, np.nan]])
print(df.isnull())
print(df.notnull())
# 実行結果
# print(sr.isnull())
0    False
1    False
2    False
3     True
4    False
dtype: bool
# print(df.notnull())
0     True
1     True
2     True
3    False
4     True
dtype: bool
# print(df.isnull())
       0      1      2      3
0  False  False  False  False
1  False   True   True  False
2  False  False  False   True
# print(df.notnull())
      0      1      2      3
0  True   True   True   True
1  True  False  False   True
2  True   True   True  False

欠損率

isnull()を応用することにより、カラム毎のの欠損率を計算できます。

import pandas as pd
import numpy as np

df = pd.DataFrame([[1., 2., 2.5, 4.5],
                   [1., np.nan, np.nan, 5.],
                   [2., 3., 3.5, np.nan],
                   [3., np.nan, 5., 6.],
                   [4., np.nan, np.nan, np.nan]])

print((df.isnull().sum() / len(df)) * 100)
# 実行結果
0     0.0
1    60.0
2    40.0
3    40.0
dtype: float64

欠損値を除外

欠損値の除外は、dropna()を使います。
欠損値のある軸が削除されます。

  • dropna(axis): axisで指定した軸に欠損値があるかを調べ、抽出して除外する。
import pandas as pd
import numpy as np

df = pd.DataFrame([[1., 2., 2.5, 4.5],
                   [1., np.nan, np.nan, 5.],
                   [2., 3., 3.5, np.nan],
                   [3., np.nan, 5., 6.],
                   [4., np.nan, np.nan, np.nan]])

df_0 = df.dropna(axis=0)
df_1 = df.dropna(axis=1)

print(df_0)
print(df_1)
# 実行結果
# print(df_0)
     0    1    2    3
0  1.0  2.0  2.5  4.5
# print(df_1)
     0
0  1.0
1  1.0
2  2.0
3  3.0
4  4.0

欠損値の穴埋め

欠損値の穴埋めは、fillna()を使います。

-fillna(value): 指定したvalueで穴埋めする。

import pandas as pd
import numpy as np

df = pd.DataFrame([[1., 2., 2.5, 4.5],
                   [1., np.nan, np.nan, 5.],
                   [2., 3., 3.5, np.nan],
                   [3., np.nan, 5., 6.],
                   [4., np.nan, np.nan, np.nan]])

df_0 = df.fillna(0) # 0で埋める
df_mean = df.fillna(df.mean()) # 平均値で埋める
df_median = df.fillna(df.median()) # 中央値で埋める

print(df_0)
print(df_mean)
print(df_median)
# 実行結果
# print(df_0)
     0    1    2    3
0  1.0  2.0  2.5  4.5
1  1.0  0.0  0.0  5.0
2  2.0  3.0  3.5  0.0
3  3.0  0.0  5.0  6.0
4  4.0  0.0  0.0  0.0
# print(df_mean)
     0    1         2         3
0  1.0  2.0  2.500000  4.500000
1  1.0  2.5  3.666667  5.000000
2  2.0  3.0  3.500000  5.166667
3  3.0  2.5  5.000000  6.000000
4  4.0  2.5  3.666667  5.166667
# print(df_median)
     0    1    2    3
0  1.0  2.0  2.5  4.5
1  1.0  2.5  3.5  5.0
2  2.0  3.0  3.5  5.0
3  3.0  2.5  5.0  6.0
4  4.0  2.5  3.5  5.0

あとがき

お疲れ様でした。今回は、欠損値の処理について簡単な説明しました。

pandas~要素編~

前書き

今回は、要素の一意性や頻度、存在の確認方法について説明します。

一意な要素

一意な要素を求めるメソッドは、以下のものです。

  • Series.unique() : Series中の一意な要素を求める。返り値は、list。
  • DataFrame.nunique() : DataFrameの中の一意な要素の個数を求める。返り値は、Series。
# sample.py
import pandas as pd

s = pd.Series([1, 2, 3, 5, 8, 2, 4, 5, 3, 4, 5, 1])
print(s.unique()) 

d = pd.DataFrame([[1, 'a'], [2, 'a'], [3, 'c'], [5, 'c'], [2, 'a'], [2, 'd'],
                  [4, 'd'], [5, 'c'], [3, 'c'], [4, 'd'], [5, 'c'], [1, 'a']])
print(d.nunique())
print(d.nunique(axis=1))

print(d.iloc[:, 0].unique()) # 0列目(Series型)を取り出し、unique()を使用
# 実行結果
# s.unique()
array([1, 2, 3, 5, 8, 4])
# d.nunique()
0    5
1    3
dtype: int64
# d.unique(axis=1)
0     2
1     2
2     2
3     2
4     2
5     2
6     2
7     2
8     2
9     2
10    2
11    2
dtype: int64
# d.iloc[:, 0].unique()
array([1, 2, 3, 5, 4])

上記の実行結果になります。DataFrameのnunique()はあまり使われません。最後の例のように、DataFrameは、一意な要素を求めたいSeriesを取り出してからunique()を使うことが多いです。

要素の頻度

要素の頻度を求めるメソッドは、以下のものです。

  • Series.value_counts() : Series中の要素の頻度を求める。返り値は、Series。
# sample.py
import pandas as pd

s = pd.Series([1, 2, 3, 5, 8, 2, 4, 5, 3, 4, 5, 1])
print(s.value_counts())

d = pd.DataFrame([[1, 'a'], [2, 'a'], [3, 'c'], [5, 'c'], [2, 'a'], [2, 'd'],
                  [4, 'd'], [5, 'c'], [3, 'c'], [4, 'd'], [5, 'c'], [1, 'a']])
print(d.iloc[:, 0].value_counts()) # 0列目(Series型)を取り出し、value_counts()を使用
# 実行結果
# s.values_counts()
5    3
4    2
3    2
2    2
1    2
8    1
dtype: int64
# d.iloc[:, 0].value_counts()
5    3
2    3
4    2
3    2
1    2
Name: 0, dtype: int64

上記の実行結果になります。Series中の要素の頻度が求められていることがわかります。
DataFrameには、value_counts()をそのまま使えません。使用したい場合は、apply()を使用します。apply()は、発展的な内容なので説明しませんが、例を載せておきます。

# sample_option.py 
import pandas as pd
d = pd.DataFrame([[1, 'a'], [2, 'a'], [3, 'c'], [5, 'c'], [2, 'a'], [2, 'd'],
                  [4, 'd'], [5, 'c'], [3, 'c'], [4, 'd'], [5, 'c'], [1, 'a']])
print(d.apply(pd.value_counts))
# 実行結果
    0      1
5  3.0    NaN
2  3.0    NaN
4  2.0    NaN
3  2.0    NaN
1  2.0    NaN
c  NaN    5.0
a  NaN    4.0
d  NaN    3.0

要素の存在

要素の存在を求めるメソッドは、以下のものです。

  • Series.isin(elements) : elements中の要素がSeriesの中に存在するかを求める。返り値は、真偽値の Series。
  • DataFrame.isin(elements) : elements中の要素がDataFrameの中に存在するかを求める。返り値は、真偽値のDataFrame。
import pandas as pd

s = pd.Series([1, 2, 3, 5, 8, 2, 4, 5, 3, 4, 5, 1])
print(s.isin([1, 3, 5]))

d = pd.DataFrame([[1, 'a'], [2, 'a'], [3, 'c'], [5, 'c'], [2, 'a'], [2, 'd'],
                  [4, 'd'], [5, 'c'], [3, 'c'], [4, 'd'], [5, 'c'], [1, 'a']])
print(d.isin([1, 3, 5, 'b', 'd']))

print(d.isin({0:[1, 3, 5], 1:['b', 'd']}))
# 実行結果
# s.isin([1, 3, 5])
0      True
1     False
2      True
3      True
4     False
5     False
6     False
7      True
8      True
9     False
10     True
11     True
dtype: bool
# d.isin([1, 3, 5, 'b', 'd'])
    0  1
0  True     False
1  False    False
2  True     False
3  True     False
4  False    False
5  False    True
6  False    True
7  True     False
8  True     False
9  False    True
10 True     False
11 True     
# d.isin({0:[1, 3, 5], 1:['b', 'd']})
    0  1
0  True     False
1  False    False
2  True     False
3  True     False
4  False    False
5  False    True
6  False    True
7  True     False
8  True     False
9  False    True
10 True     False
11 True     False

上記の実行結果になります。DataFrameは、引数にlistとかdictを与えることができます。isin()関数は、フィルタリングするのによく使います。例を載せておきます。

# sample_option
import pandas as pd

s = pd.Series([1, 2, 3, 5, 8, 2, 4, 5, 3, 4, 5, 1])
s_ = s[s.isin([1, 3, 5])] # 要素が1,3,5だけを取り出す
print(s_)
# 実行結果
0     1
2     3
3     5
7     5
8     3
10    5
11    1
dtype: int64

あとがき

お疲れさまでした。次回は、欠損値の処理について説明します。

pandas~要約統計量編~

前書き

前回に引き続き、今回もpandasの説明をします。今回は、欠損値と要約統計量を求めるメソッドについて説明(紹介)します。

欠損値

まずは、サンプルをみましょう。

# sample.py
import pandas as pd
import numpy as np

sdata = {'A': 80, 'B': 70, 'C': 60, 'D': 0}
stage = ['S', 'A', 'B', 'C', 'D']
data = pd.Series(sdata, index=stage)

print(data)
# 実行結果
S     NaN # 欠損値
A    80.0
B    70.0
C    60.0
D     0.0
dtype: float64

実行結果は上記のようになります。この例の場合は、sdataの中に見つかった4つのデータ(A, B, C, D)は正しくインデックスと対応付けられています。'S'に対応するデータは、sdataに存在しないためNaN(not a number)となります。pandasは、NaNを欠損値またはNA値として扱います。対応するデータが存在しないときは、欠損値が自動的に補完されます。

要約統計量

pandasには、要約統計量を計算する様々なメソッドがあります。ここでは、重要なものをいくつか説明します。

# sample.py
import pandas as pd
import numpy as np

# np.nanにより欠損値にすることができる
data = pd.DataFrame([[1.0, 2.0], [np.nan, 4.0], [5.0, np.nan], [7.0, 8.0]],
                    index=['one', 'two', 'three', 'four'],
                    columns=['a', 'b'])

print(data)

print(data.describe()) # 複数の要約統計量を計算する

print(data.sum()) # 行の合計値
print(data.sum(axis=1)) # 列の合計値

print(data.mean()) # 行の平均値

print(data.std()) # 行の標準偏差

print(data.count()) # 行の欠損値ではない要素の数
# 実行結果
# print(data)
         a    b
one    1.0  2.0
two    NaN  4.0
three  5.0  NaN
four   7.0  8.0
# print(data.describe())
              a         b
count  3.000000  3.000000
mean   4.333333  4.666667
std    3.055050  3.055050
min    1.000000  2.000000
25%    3.000000  3.000000
50%    5.000000  4.000000
75%    6.000000  6.000000
max    7.000000  8.000000
# print(data.sum())
a    13.0
b    14.0
dtype: float64
# print(data.sum(axis=1))
one       3.0
two       4.0
three     5.0
four     15.0
dtype: float64
# print(data.mean())
a    4.333333
b    4.666667
dtype: float64
# print(data.std())
a    3.05505
b    3.05505
dtype: float64
# print(data.count())
a    3
b    3
dtype: int64

実行結果は上記のようになります。describe()は複数の要約統計量を計算します。sum()・mean()・std()は合計値、平均値、標準偏差を計算します。また、axis=1のように指定することにより、計算対象の軸を変更できます。count()は欠損値以外の要素の個数を計算します。

よく使う要約統計量の一覧は以下になります。

メソッド 意味
describe 複数の要約統計量を求める
count NA値ではない要素の個数を求める
min, max 最小値・最大値を求める
argmin, argmax 最小値・最大値が得られた場所のインデックスを求める
sum 合計値を求める
mean 平均値を求める
median 中央値を求める
var 分散を求める
std 標準偏差を求める
cumsum 累積和を求める

また、上記のメソッドにおいてdescribe以外はaxisにより計算軸を指定することができます。axis=0が行・axis=1が列です。デフォルトではaxis=0となっています。そのほかにも、指定できるオプションはありますが、使用頻度は高くないので説明しません。

あとがき

お疲れさまでした。今回は、欠損値と要約統計量を求めるメソッドについて説明しました。次回は、欠損値の処理について説明したいと思います。