1
1

More than 3 years have passed since last update.

pandas勉強 その1(自己学習用)

Last updated at Posted at 2020-06-07

分析のためにpythonを習得しているので、具体的な集計・分析手法や前処理の方法を学んできたが
ここらでよく使うpandasについてちゃんと勉強してみよう、と思いメモ。
知っている人には当たり前なんだろうけど、どこかふわふわした理解のままではスッキリしないので。

参考文献はこちら
Pythonによるデータ分析入門

参考文献を見ながら、自分の手でコード書いて実行。
重要な箇所を見て気付いたことを少し書く、というスタイルですので無駄に長いです。。。
※引用箇所が参考文献の本文です。

シリーズ(Series)

よく出てきて混乱を起こしたやつ。わかったようなわからないような。
Numpyのarrayとの違いがよくわからなかった。

インデックスについて

シリーズは1次元の配列のようなオブジェクトです
連続した値と、それに関連付けられたインデックスというデータラベルの配列が含まれます

おお、なるほど。知らなかった、インデックスがセットになってくるのが大事なのか。

x = pd.Series([1,2,3,4])
x

結果
0    1
1    2
2    3
3    4

1、2、3、4はシリーズのデータで、0、1、2、3というのがインデックスなんですね。
これはインデックスを指定しなかったからこうなるようでインデックスを指定することもできる。

x = pd.Series([1,2,3,4], index = ['a','b','c','d'])
x

結果
a    1
b    2
c    3
d    4

インデックスを指定したのでちゃんと変わっています。

Numpyの配列と違って、1つの値や複数の値を参照するときにインデックスのラベルを使って指定することができます。

そういえばそんなことしていたな、と改めて納得。道場で基礎を磨くのはやっぱり悪くない。

x['b']

結果
2

計算

条件指定によるフィルタリング、スカラー値の掛け算、数学的な関数の適用、などのNumpyの関数
やNumpy風の操作を行った場合も、インデックスとデータ値との関連は保持されます。

x[x > 2]

結果
c    3
d    4
x * 2

結果
a    2
b    4
c    6
d    8
np.exp(x)

結果
a     2.718282
b     7.389056
c    20.085537
d    54.598150

計算されて値は変わってるけどインデックスは変わってないですね。理解。

シリーズをインデックスとデータ値がマッピングされた固定長の順序つきディクショナリととらえ
る見方もあります。ディクショナリを使う多くの文脈では、シリーズを使うことができるでしょう。

'b' in x

結果
True
'e' in x

結果
False

いろいろな作成方法

pythonのディクショナリ形式のデータがある場合は、それを使ってシリーズを作成することができます。

y = {'a': 100, 'b': 200, 'c': 300, 'd': 400}
z = pd.Series(y)
z

結果
a    100
b    200
c    300
d    400

ここまでやって、エクセルのINDEX関数で参照していたのが、今作っているインデックスなのかなと気付く。理解。
今作ったシリーズに対して

w = ['a','b','C','D']
t = pd.Series(y, index = w)
t

結果
a    100.0
b    200.0
C      NaN
D      NaN

インデックスを付け替えようとすると、元のインデックスと対応しているデータはそのままデータ値で、
そうでない箇所(ここでは大文字のCとD)は、NaNになっています。

NaNはpandasでは欠損値、または、NA値として扱われます。
また'c'と'd'は、指定したwには含まれていないため、作成されたシリーズからは除外されています。

そんな処理になっていたのか。これも知らなかった。

pandasのisnull関数notnull関数は欠損値を特定するために使います。

pd.isnull(t)

結果
a    False
b    False
C     True
D     True
pd.notnull(t)

結果
a     True
b     True
C    False
D    False

シリーズはこれらの関数をインスタンスメソッドとしても持っています

t.isnull()

結果
a    False
b    False
C     True
D     True

算術演算をするときに別々のインデックス付けされたデータが自動的に整形される、というものがあります。

z

結果
a    100
b    200
c    300
d    400
t

結果
a    100.0
b    200.0
C      NaN
D      NaN
z + t

結果
C      NaN
D      NaN
a    200.0
b    400.0
c      NaN
d      NaN

シリーズのインデックスは代入して置き換えることができます。

t.index = ['1','2','3','4']
t

結果
1    100.0
2    200.0
3      NaN
4      NaN

ちゃんとインデックスが変わっています。

データフレーム(DataFrame)

これもわかるようなわからないようなの代表。

データフレームはテーブル形式のデータ構造を持ち、順序づけられた列を持っています。各列には
別々の型(数値型、文字列型、ブール型など)を持たせることができます。データフレームは行と列の
両方にインデックスを持っています

1列の中では同じ型です、ということかな、どのようにデータを持っているかが大事なのか。
行方向にも列方向にもインデックスがある→インデックスの組み合わせでデータを特定できそう。

データフレームはシリーズをバリューとしても持つディクショナリと見ることができます。
(各シリーズのインデックスを全体で共有しているようなイメージです)

ちょっとイメージが湧かないので、今はスルーします。

作成方法

一般的な方法は同じ長さを持つリスト型のバリューを持ったディクショナリか、Numpyの配列を使う方法です。

data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'],
        'year': [2000, 2001, 2002, 2001, 2002, 2003],
        'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}

frame = pd.DataFrame(data)
frame

結果
    state   year    pop
0   Ohio    2000    1.5
1   Ohio    2001    1.7
2   Ohio    2002    3.6
3   Nevada  2001    2.4
4   Nevada  2002    2.9
5   Nevada  2003    3.2

操作

列の並べ替え

列の順番を指定すると、データフレームの列はその順番で並びます。

pd.DataFrame(data, columns=['year', 'state', 'pop'])

結果
    year    state   pop
0   2000    Ohio    1.5
1   2001    Ohio    1.7
2   2002    Ohio    3.6
3   2001    Nevada  2.4
4   2002    Nevada  2.9
5   2003    Nevada  3.2

左から指定した順番に並んでいることがわかります。

データの無い列の指定

指定した列がデータを持っていない場合、その列は結果として欠損値が代入されます

frame2 = pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'],
                      index = ['one','two','three','four','five','six'])

frame2

結果
        year    state   pop  debt
one     2000    Ohio    1.5   NaN
two     2001    Ohio    1.7   NaN
three   2002    Ohio    3.6   NaN
four    2001    Nevada  2.4   NaN
five    2002    Nevada  2.9   NaN
six     2003    Nevada  3.2   NaN

もともとなかった’debt’には欠損値のNaNが代入されています。

データの取り出し

データフレームの列はディクショナリ風の参照や、属性指定をすることで、シリーズとして
取り出すことができます。

frame2['state']

結果
one        Ohio
two        Ohio
three      Ohio
four     Nevada
five     Nevada
six      Nevada

取り出したシリーズはデータフレームの持っていたインデックスと同じインデックスを持ち、name属性も適切に設定されています。
行も一夜名前で参照することができます。名前で参照するときには、locという属性を使います。

frame2.loc['three']

結果
year     2002
state    Ohio
pop       3.6
debt      NaN

ここでは'three'という名前で参照しているので、'three'行のデータがカラム名と共に表示されています。

データの代入

列の値は代入して変更できます。

frame2['debt'] = 16.5
frame2

結果
        year    state   pop  debt
one     2000    Ohio    1.5   16.5
two     2001    Ohio    1.7   16.5
three   2002    Ohio    3.6   16.5
four    2001    Nevada  2.4   16.5
five    2002    Nevada  2.9   16.5
six     2003    Nevada  3.2   16.5

先ほどはNaN値であった'debt'に16.5が代入されているのがわかります。

frame2['debt'] = np.arange(6.)
frame2

結果
        year    state   pop  debt
one     2000    Ohio    1.5   0.0
two     2001    Ohio    1.7   1.0
three   2002    Ohio    3.6   2.0
four    2001    Nevada  2.4   3.0
five    2002    Nevada  2.9   4.0
six     2003    Nevada  3.2   5.0

列の長さが一致していれば、np.arangeを列指定で代入することもできるんですね。
なんとなくやっていたことの理解が深まる。

シリーズを列に代入する場合は、ラベルはデータフレームのインデックスに従って正確に一致
するように代入が行われ、データフレームのインデックスに対応するものがない場合は、欠損値が
挿入されます。

val = pd.Series([-1.2, -1.5, -1.7], index = ['two', 'four', 'five'])
frame2['debt'] = val
frame2

結果
        year    state   pop  debt
one     2000    Ohio    1.5   Nan
two     2001    Ohio    1.7   -1.2
three   2002    Ohio    3.6   NaN
four    2001    Nevada  2.4   -1.5
five    2002    Nevada  2.9   -1.7
six     2003    Nevada  3.2   NaN

おお、確かにインデックスが一致しているのでその箇所だけ代入されています。

存在しない列への代入(列の生成)、列の削除

存在しない列に代入を行うと、新しい列が作成されます。
delキーワードを使うと、ディクショナリと同じように列を消すことができます。

frame2['eastern'] = frame2.state == 'Ohio'
frame2

結果
        year    state   pop  debt    eastern
one     2000    Ohio    1.5   NaN    True
two     2001    Ohio    1.7  -1.2    True
three   2002    Ohio    3.6   NaN    True
four    2001    Nevada  2.4  -1.5    False
five    2002    Nevada  2.9  -1.7    False
six     2003    Nevada  3.2   NaN    False

もともとなかった'eastern'に代入しようとすると、新しく列が生成され、代入したいデータが入っています。
列の追加は確かにこんな風にやってた。仕組みがわかると面白い。

del frame2['eastern']
frame2

結果
        year    state   pop  debt    
one     2000    Ohio    1.5   NaN   
two     2001    Ohio    1.7  -1.2   
three   2002    Ohio    3.6   NaN    
four    2001    Nevada  2.4  -1.5    
five    2002    Nevada  2.9  -1.7    
six     2003    Nevada  3.2   NaN    

ちゃんと消えていますね。

ネストしたディクショナリ

ネストしたディクショナリをデータフレームに渡すと、pandasは外側のディクショナリのキーを
列のインデックスとして解釈し、内側のインデックスのキーを行のインデックスとして解釈します。

pop = {'Nevata': {2001: 2.4, 2002: 2.9},
       'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}

frame3 = pd.DataFrame(pop)
frame3

結果
     Nevata  Ohio
2001    2.4   1.7
2002    2.9   3.6
2000    NaN   1.5 

外側のディクショナリのキー = 'Nevada'、'Ohio'の2つですね。これが列のインデックスになっています。
内側のインデックスのキー = '2000'、'2002'と言った年データです。これが行のインデックスになっています。

行列の入れ替え

データフレームはNumpyの配列と同様な文法で転置することができます。

frame3.T

結果
        2001  2002  2000
Nevata   2.4   2.9   NaN
Ohio     1.7   3.6   1.5 

行と列が入れ替わっているのがわかります。

value参照

value属性を参照すると、データフレームの中のデータが2次元のndarrayとして戻されます。

frame3.values

結果
array([[2.4, 1.7],
       [2.9, 3.6],
       [nan, 1.5]])

インデックスオブジェクト

pandasのインデックスオブジェクトは、軸のラベルやその他のメタデータ(軸のname属性やnames属性など)を
保持する役目を持っています。シリーズやデータフレームを初期化するときに、配列やシーケンスなどで指定した
ラベルは、内部的にはインデックスオブジェクトに変換されます。

obj = pd.Series(range(3), index = ['a','b', 'c'])
index = obj.index
index

結果
Index(['a', 'b', 'c'], dtype='object')

説明のまんまですね。インデックスがオブジェクトになっています。

インデックスオブジェクトは配列と似ているだけでなく、固定長のセットしても機能します。

frame3.columns

結果
Index(['Nevata', 'Ohio'], dtype='object')
'Ohio' in frame3.columns

結果
True

まとめ

この本ですが、最初読んだとき意味不明で泣きそうでしたが、pythonの実際の操作をやってみて
少し慣れた今見るととても理解が進みました。
とりあえず手を動かしてみる、その後しっかり理解する、という順番で学んでいくの良さそうです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1