LoginSignup
14

More than 3 years have passed since last update.

Pandasの基本的な使い方

Last updated at Posted at 2019-06-24

概要

https://openbook4.me/projects/183
にまとめていた内容のうち基礎的な部分を移動

pandas

pythonでデータ解析とかするのに便利なlibrary.
numpyも使うので, ここでは両方共importした状態にしておく.

import numpy as np
import pandas as pd

Series

軸にラベルを付けた1次元の配列.

>> pd.Series([1,2,3])
0    1
1    2
2    3
dtype: int64

>> s = pd.Series([1,2,3], index=['a','b','c'])
>> s
a    1
b    2
c    3
dtype: int64

>> s.index
Index([u'a', u'b', u'c'], dtype='object')

>> s.max()   # 最大値
3

>> s.min()   # 最小値
1

>> s.mean()   # 平均値
2.0

>> s.median()   # 中央値
2.0

>> s.var()   # 分散
1.0

>> s.sum()   # 合計値
6

>> s.mod(2)   # modの計算, この場合2で割った余り
a    1
b    0
c    1

>> s.cumsum()   # 累積にする. 累積のグラフを作るとき便利
a    1
b    3
c    6
dtype: int64

>> s.apply(lambda x: x*3)   # 特定の関数を各値に対して適応
a    3
b    6
c    9
dtype: int64

>> s.map({1: 10, 2: 200})   # 引数で与えた値に対応する値を変換
a     10
b    200
c    NaN
dtype: float64

>> s.argmax()   # 最大値のindexを取得
'c'

>> s.argmin()   # 最小値のindexを取得
'a'

>> s.tolist()   # listに変更
[1, 2, 3]

>> s.to_dict()   # dictonaryに変更
{'a': 1, 'b': 2, 'c': 3}

>> s.to_json   # jsonに変更
'{"a":1,"b":2,"c":3}'

DataFrame

DataFrameの作成

df = pd.DataFrame([[1,4,7],[2,5,8],[3,6,9]],
                  index=['i1','i2','i3'],
                  columns=list("abc"))
>> df
    a  b  c
i1  1  4  7
i2  2  5  8
i3  3  6  9

値の操作

範囲を指定して取り出す

行に関連する操作は、.ixを使う。

>> df
    a  b  c
i1  1  4  7
i2  2  5  8
i3  3  6  9

# 指定した行の取り出し。index名かindex番号で与えられる。
>> df.ix['i1']
a    1
b    4
c    7
Name: i1, dtype: int64

>> df.ix[1]
a    2
b    5
c    8
Name: i2, dtype: int64

# 2つ目のparameterに列を渡すことで、行を取得できる。
>> df.ix['i1','a']
 1

# : は全指定する。(R, scilabと対応)
>> df.ix[:, 'a']
i1    1
i2    2
i3    3
Name: a, dtype: int64

# 複数の指定も配列で可能。
>> df.ix[[1,2], ['b','c']]
    b  c
i2  5  8
i3  6  9

>> df.ix[[1,2], [1,2]]
    b  c
i2  5  8
i3  6  9

列に関する操作は[column名]で渡す。

>> df['a']
i1    1
i2    2
i3    3
Name: a, dtype: int64

# arrayとして取得する。
>> df['a'].values
array([1, 2, 3])

# さらにindex名を指定することで値として取得できる。
>> df['a']['i3']
 3

DataFrameをtableとみなして、位置指定から値を明示的に取る方法。

>> df.iloc[0,0]
1
(df.ix[0,0]と同じ)

# 列の取得
>> df.iloc[2]
a    3
b    6
c    9
Name: i3, dtype: int64

条件を満たすに要素に値を代入

例えば行列において、1より大きい値を全部1にしたい場合

>> a = pd.DataFrame(np.random.randint(3, size=(5,3)))
   0  1  2
0  0  2  1
1  2  0  1
2  0  0  2
3  2  1  0
>> b[b>1]   # 条件を満たすものだけを抽出したDataFrame
    0   1   2
0 NaN   2 NaN
1   2 NaN NaN
2 NaN NaN   2
3   2 NaN NaN
>> b[b>1] = -1  # 条件をみたすものに1を代入
>> b
   0  1  2
0  0  1  1
1  1  0  1
2  0  0  1
3  1  1  0

NaNの処理

NaNの削除

dropnaで削除できる

>> df
    a   b  c
0   1   3  5
1   2 NaN  6
2 NaN   4  7

>> df.dropna()   # NaNを含む行を削除
   a  b  c
0  1  3  5

>> df.dropna(axis=1)   # NaNを含む列を削除
   c
0  5
1  6
2  7

>> df.dropna(subset=['b'])   # 特定カラムを指定することも可能
    a  b  c
0   1  3  5
2 NaN  4  7

NaNを埋める

fillnaを使う。fillnaで指定した値で埋めることができる以外に、
直前の値で補完(pad/ffill)、直後の値で補完(bfill)などがある。

>> df
    a   b  c
0   1   3  5
1   2 NaN  6
2 NaN   4  7

>> df.fillna(-1)
   a  b  c
0  1  3  5
1  2 -1  6
2 -1  4  7


>> df.fillna(method='pad')
   a  b  c
0  1  3  5
1  2  3  6
2  2  4  7

>> df.fillna(method='bfill')
    a  b  c
0   1  3  5
1   2  4  6
2 NaN  4  7

misssing valueの前後の線形の値で埋めたい場合は pd.Series.interpolate をapplyしてやる。

>> df
    a   b
0   1   2
1   2 NaN
2 NaN   3

>> df.apply(pd.Series.interpolate)
   a    b
0  1  2.0
1  2  2.5
2  2  3.0

重複した値の処理

duplicatedで重複を調べれる。重複を調査するcolumnを指定することも可能。

>> df
   0  1
0  A  1
1  A  1
2  A  2
3  B  3
4  B  4

>> df.duplicated()
0    False
1     True
2    False
3    False
4    False
dtype: bool

>> df.duplicated(0)
0    False
1     True
2     True
3    False
4     True
dtype: bool

>> df.duplicated(1)
0    False
1     True
2    False
3    False
4    False
dtype: bool

drop_duplicatesで重複した値を削除できる。duplicatedと同様にcolumn指定も可能。
take_last=Trueオプションで重複した場合に最後の値を取ることができる。

>> df.drop_duplicates()
   0  1
0  A  1
2  A  2
3  B  3
4  B  4

>> df.drop_duplicates(0)
   0  1
0  A  1
3  B  3

>> df.drop_duplicates(0, take_last=True)
   0  1
2  A  2
4  B  4

Pandas: DataFrameの変形

ここではDataFrameの形を変える方法を順に見ていく。

次のようなdfについて処理する。

df = pd.DataFrame(np.reshape(np.arange(9), (3,3)),
                  columns=['a', 'b', 'c'])
>> df
   a  b  c
0  0  1  2
1  3  4  5
2  6  7  8

DataFrameの一部を取る

n行を取る。

# 最初のn行を取る。
>> df.head(2)
   a  b  c
0  0  1  2
1  3  4  5

# 終わりn行取る。
>> df.tail(2)
   a  b  c
1  3  4  5
2  6  7  8

index, columnを取る。

>> df.index
Int64Index([0, 1, 2], dtype='int64')
>> df.columns
Index([u'a', u'b', u'c'], dtype='object')

DataFrameの形式を変える。

indexとcolumnを逆にする。

>> df.T
   0  1  2
a  0  3  6
b  1  4  7
c  2  5  8

この操作は非破壊的なので、df自体が反転するわけではない。

(使用するときは、rdf = df.Tのようにすればよい。)

index, columnの順番を反転させる。

# columnについての順番を逆転させる。
>> df.sort_index(axis=1, ascending=False)
   c  b  a
0  2  1  0
1  5  4  3
2  8  7  6

index, columnに対して、値の順番を並び替える。

# 大きい順に並び替える。(今回だと全部逆転したように見えるけれど...)
>> df.sort(columns='b', ascending=False)
   a  b  c
2  6  7  8
1  3  4  5
0  0  1  2

# 小さい順に並び替える。(今回だと変わらないけれど...)
>> df.sort(columns='b')
   a  b  c
0  0  1  2
1  3  4  5
2  6  7  8

各値を取る

df[],df.loc[],df.iloc[],...

などなど前章でやった!

マスクする(ほしい条件のもとで、dfから選びとる。)

# df["条件文をかく"]という形。
>> df.a
0    0
1    3
2    6
# に対して、2以上の1,2とついたindexのみ取ってくる。

>> df[df.a>2]
   a  b  c
1  3  4  5
2  6  7  8

全体に対するoperationだと条件に合うもの、合わないもの(NaN)を表示する。

# 3より大きい所をとってくる
>> df[df > 3]
    a   b   c
0 NaN NaN NaN
1 NaN   4   5
2   6   7   8
# 3より大きいところだけ、2倍する。
>> df[df > 3] = df*2
>> df
    a   b   c
0   0   1   2
1   3   8  10
2  12  14  16

columnの追加

よく使うので重要です!

>> df['e'] = ['one','two','three']
>> df
   a  b  c      e
0  0  1  2    one
1  3  4  5    two
2  6  7  8  three

NaNのdataを含むものを消去する。

# NaNのものを消去する。
>> df[df > 3].dropna(how='any')
   a  b  c
2  6  7  8
# NaNを別のもので埋める。

>> df[df > 3].fillna('Ice')
     a    b    c
0  Ice  Ice  Ice
1  Ice    4    5
2    6    7    8

DataFrameをくっつける

df2を作成する。

>> df2 = pd.DataFrame(np.reshape(np.arange(6), (3,2)),
                     columns=['e', 'f'])
>> df2
   e  f
0  0  1
1  2  3
2  4  5

concat

列でくっつける
>> newdf = pd.concat([df, df2],axis=1)
>> newdf
   a  b  c  e  f
0  0  1  2  0  1
1  3  4  5  2  3
2  6  7  8  4  5
行についてくっつける
>> newdf = pd.concat([df, df2],axis=0)
>> newdf
    a   b   c   e   f
0   0   1   2 NaN NaN
1   3   4   5 NaN NaN
2   6   7   8 NaN NaN
0 NaN NaN NaN   0   1
1 NaN NaN NaN   2   3
2 NaN NaN NaN   4   5

append

行に対して追加する。(dataを増やす)

>> result = df.append(df2)
>> result
    a   b   c   e   f
0   0   1   2 NaN NaN
1   3   4   5 NaN NaN
2   6   7   8 NaN NaN
0 NaN NaN NaN   0   1
1 NaN NaN NaN   2   3
2 NaN NaN NaN   4   5

DataFrameのindex, columnを大きく変える。

pivot table

pivot_tableでは、既存のカラムから新しくindex、columnsを定義したDataFrameを作成できる。

>> df = pd.DataFrame({'col1' : ['one', 'two', 'three', 'four'] * 3,
                    'col2' : ['A', 'B', 'C'] * 4,
                    'col3' : ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] * 2,
                    'col4' : np.arange(1, 13),
                    'col5' : np.arange(13, 25)})
>> df
     col1 col2 col3  col4  col5
0     one    A  foo     1    13
1     two    B  foo     2    14
2   three    C  foo     3    15
3    four    A  bar     4    16
4     one    B  bar     5    17
5     two    C  bar     6    18
6   three    A  foo     7    19
7    four    B  foo     8    20
8     one    C  foo     9    21
9     two    A  bar    10    22
10  three    B  bar    11    23
11   four    C  bar    12    24

col1をindex、col2をcolumnsでcol4を値としたdfは以下のように作る。

>> df.pivot_table(values='col4', index='col1', columns='col2')

col2    A   B   C
col1
four    4   8  12
one     1   5   9
three   7  11   3
two    10   2   6

df.pivot_tableでなく、pd.pivot_tableでも同様の操作ができる。

>> pd.pivot_table(df, values='col4', index='col1', columns='col2')

col2    A   B   C
col1
four    4   8  12
one     1   5   9
three   7  11   3
two    10   2   6

pivot_tableでは、indexやcolumnを階層化することができる。
ここでは、col1とcol2をmulti-index、col3をcolumn, col4を表の値としたtableに作り変える。

>> df.pivot_table(values='col4', index=['col1', 'col2'], columns=['col3'])

col3         bar  foo
col1  col2
four  A      4.0  NaN
      B      NaN  8.0
      C     12.0  NaN
one   A      NaN  1.0
      B      5.0  NaN
      C      NaN  9.0
three A      NaN  7.0
      B     11.0  NaN
      C      NaN  3.0
two   A     10.0  NaN
      B      NaN  2.0
      C      6.0  NaN

pivot_tableにて、一つのセルに値が複数入る場合がある。
この場合、デフォルトではmean、つまり平均値が集計される。
もし集計方法を変えたい場合はaggfuncオプションに関数を与えれば良い。

>> df.pivot_table(values='col4', index='col2', columns='col3')

col3  bar  foo
col2
A       7    4
B       8    5
C       9    6

>> df.pivot_table(values='col4', index='col2', columns='col3', aggfunc=np.sum)

col3  bar  foo
col2
A      14    8
B      16   10
C      18   12

>> df.pivot_table(values='col4', index='col2', columns='col3', aggfunc=np.max)

col3  bar  foo
col2
A      10    7
B      11    8
C      12    9

pivot

pivot_tableでは値の候補が複数ある場合の処理を気にしなければならないが、
値がかぶらないことが保証されているときはpivotで処理するのが簡単である。
pivotではpivot_tableと同様に新しくindexとcolumnとvalueになるcolumnを指定する。

>> df.pivot(values='col4', index='col1', columns='col2')

col2    A   B   C
col1
four    4   8  12
one     1   5   9
three   7  11   3
two    10   2   6

pivotの場合、値の候補が複数ある場合は、エラーがでる。

>> df.pivot(values='col4', index='col2', columns='col3')

ValueError: Index contains duplicate entries, cannot reshape

stack

Multi-indexのDataFrameを作成する。

>> tuples = list(zip(*[['bar', 'bar', 'baz', 'baz',
                      'foo', 'foo', 'qux', 'qux'],
                     ['one', 'two', 'one', 'two',
                      'one', 'two', 'one', 'two']]))
>> tuples
[('bar', 'one'),
 ('bar', 'two'),
 ('baz', 'one'),
 ('baz', 'two'),
 ('foo', 'one'),
 ('foo', 'two'),
 ('qux', 'one'),
 ('qux', 'two')]
>> index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
>> index
MultiIndex(levels=[[u'bar', u'baz', u'foo', u'qux'], [u'one', u'two']],
           labels=[[0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 0, 1, 0, 1, 0, 1]],
           names=[u'first', u'second'])

>> df = pd.DataFrame(np.random.randn(8, 2), index=index, columns=['A', 'B'])
>> df
                     A         B
first second
bar   one     0.201808  0.617744
      two    -0.272022  1.012488
baz   one     0.944162 -0.243223
      two     0.259391  0.064546
foo   one     0.222640  0.283878
      two    -0.975535  0.461281
qux   one    -0.437626  0.366836
      two    -0.029409  0.141013

これをcolumnについて並列化する。

>> stacked = df.stack()
>> stacked
first  second
bar    one     A    0.201808
               B    0.617744
       two     A   -0.272022
               B    1.012488
baz    one     A    0.944162
               B   -0.243223
       two     A    0.259391
               B    0.064546
foo    one     A    0.222640
               B    0.283878
       two     A   -0.975535
               B    0.461281
qux    one     A   -0.437626
               B    0.366836
       two     A   -0.029409
               B    0.141013

>> stacked[0:3]
first  second
bar    one     A    0.201808
               B    0.617744
       two     A   -0.272022
A, Bというlabelを合わせてぐっちゃぐちゃで縦に処理できる

unstack

stackの逆。戻すレベルを指定する。

>> stacked_unstacked = stacked.unstack(0)
>> stacked_unstacked
first          bar       baz       foo       qux
second
one    A  0.201808  0.944162  0.222640 -0.437626
       B  0.617744 -0.243223  0.283878  0.366836
two    A -0.272022  0.259391 -0.975535 -0.029409
       B  1.012488  0.064546  0.461281  0.141013


>> stacked_unstacked = stacked.unstack(1)
>> stacked_unstacked
second        one       two
first
bar   A  0.201808 -0.272022
      B  0.617744  1.012488
baz   A  0.944162  0.259391
      B -0.243223  0.064546
foo   A  0.222640 -0.975535
      B  0.283878  0.461281
qux   A -0.437626 -0.029409
      B  0.366836  0.141013

get_dummies

ダミー変数を作成する。カテゴリカルデータで機械学習などをしたいときなどに便利。

>> df = pd.DataFrame({'A' : ['one', 'one', 'two', 'three'] * 3,
                    'B' : ['A', 'B', 'C'] * 4,
                    'C' : ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] * 2})
>> df
        A  B    C
0     one  A  foo
1     one  B  foo
2     two  C  foo
3   three  A  bar
4     one  B  bar
5     one  C  bar
6     two  A  foo
7   three  B  foo
8     one  C  foo
9     one  A  bar
10    two  B  bar
11  three  C  bar

>> df.C.str.get_dummies()

    bar  foo
0     0    1
1     0    1
2     0    1
3     1    0
4     1    0
5     1    0
6     0    1
7     0    1
8     0    1
9     1    0
10    1    0
11    1    0

もしくは、

>> pd.get_dummies(df.C)

    bar  foo
0     0    1
1     0    1
2     0    1
3     1    0
4     1    0
5     1    0
6     0    1
7     0    1
8     0    1
9     1    0
10    1    0
11    1    0

df.Cにはbar, fooという文字列が入っており、それぞれbar, fooというカラムを
もつ、DataFrameを作成している。
値は、0, 1が入っているが、各インデックスに対して、barならbarカラムを1にしfooカラムを0にし、
fooならばfooカラムを1としbarカラムを0としている。
つまり、各indexがbarに属しているかfooに属しているかを0, 1に変更している。

そのままの値をカラム名としたくない場合はprefixをつけることも可能。

>> pd.get_dummies(df.C, prefix='category')

    category_bar  category_foo
0              0             1
1              0             1
2              0             1
3              1             0
4              1             0
5              1             0
6              0             1
7              0             1
8              0             1
9              1             0
10             1             0
11             1             0

Pandas: DataFrameに数式をあてはめる

前回までと同じく

>> df = pd.DataFrame(np.reshape(np.arange(9), (3,3)),
                     columns=['a', 'b', 'c'])
>> df
   a  b  c
0  0  1  2
1  3  4  5
2  6  7  8

を使って数式による計算を適用してみる。

apply

とてもよくお世話になるメソッド。

累積(np.cumsum)

columnについて累積をとる。

>> df.apply(np.cumsum)
   a   b   c
0  0   1   2
1  3   5   7
2  9  12  15

根号(np.sqrt)

>> df.apply(np.sqrt)
          a         b         c
0  0.000000  1.000000  1.414214
1  1.732051  2.000000  2.236068
2  2.449490  2.645751  2.828427

lambda関数

# 各列ごとの最大と最小の差
>> df.apply(lambda x: x.max() - x.min())
a    6
b    6
c    6

基礎統計

平均を取る

列について
>> df.mean(0)
a    3
b    4
c    5
行について
>> df.mean(1)
0    1
1    4
2    7

ファイル操作

ファイルからデータを読み込んだり、ファイルにデータを吐き出すことがよくあるので、
ファイル入出力の説明

ファイル出力

Series

to_csv関数を使う.

>> s
a    1
b    2
c    3
dtype: int64
>> s.to_csv('output.csv')

とすると, index付きのファイルが出力される.

a,1
b,2
c,3

indexを出力したくない場合は, index=False を指定する.

>> s.to_csv('output.csv', index=False)

tsvなど他の形式にしたい場合はsep(separatorの略)で区切り文字を変更する.

>> s.to_csv('output.tsv', sep='\t')

DataFrame

Seriesと同様にto_csvを使う.

>> df
   a  b  c
0  1  3  5
1  2  4  6

>> df.to_csv('output.csv')

headerも含めて出力される.

,a,b,c
0,1,3,5
1,2,4,6

headerを省略したい場合は, header=False を指定する.

>> df.to_csv('output.csv', header=False)
0,1,3,5
1,2,4,6

Seriesの場合と同様に, index=False も指定できる.

>> df.to_csv('output.csv', index=False)
a,b,c
1,3,5
2,4,6

区切り文字も同様に sep にて変更。

>> df.to_csv('output.dat', sep='|')
|a|b|c
0|1|3|5
1|2|4|6

ファイル入力

デフォルトではseparatorがcommaになるので、tsvファイルの場合などはsep="\t"と設定する必要がある。
headerがないファイルの場合はheader=Noneと指定しておかないと1行目が勝手にheaderとして認識されてしまうので注意。

pd.read_csv("data.tsv", sep="\t", header=None)

明示的にheaderを指定してもよい

pd.read_csv("data.tsv", sep="\t", names=["column1", "column2"])

indexが入っているファイル場合, indexが入っている列の番号を指定する.

pd.read_csv("data.csv", index_col=0)

入出力例

indexつきheaderつきのファイルの入出力

>> df = pd.DataFrame({'a': [1,2], 'b': [3,4], 'c': [5,6]})
>> df
   a  b  c
0  1  3  5
1  2  4  6

>> df.to_csv('sample.csv')

これでsample.csvができる.

sample.csv
,a,b,c
0,1,3,5
1,2,4,6

sample.csvを読み込んでもとのDataFrameに戻すには, index_colを指定して読み込む.

>> pd.read_csv('sample.csv', index_col=0)
   a  b  c
0  1  3  5
1  2  4  6

このときindex_colを指定しないと別途indexが指定されてしまう。

>> pd.read_csv('sample.csv')
   Unnamed: 0  a  b  c
0           0  1  3  5
1           1  2  4  6

データベース連携

実務上では, データベースからデータを取得して処理したいことがある。
ここではpandasでどのようにデータを取得して、DataFrameに格納するかを説明する。

postgresqlからデータを取得する

pandasにはsqlに接続するための pandas.io.sql がある。
これにpostgresql接続用のライブラリpsycopg2を利用して接続する。

import pandas as pd
import psycopg2

connection = psycopg2.connect(host='host', dbname='database', user='username', password='password')
result = pd.read_sql("SELECT * FROM users", connection)

MySQLを使用する場合

MySQLを使用する場合は MySQLdb を利用する。connectionの部分をMySQLdb用に変更する.

import pandas as pd
import MySQLdb

connection = MySQLdb.connect(host='host', dbname='database', user='username', password='password')
result = pd.read_sql("SELECT * FROM users", connection)

read_sql

データベースに接続しその結果をtsvで吐き出す

import pyodbc
import pandas.io.sql as psql
connection = pyodbc.connect(uid=user, dsn='instance', database='database', pwd='password')
column_data = psql.read_sql("SELECT * FROM hoge", connection)
print "\t".join(map(str,list(column_data.ix[0])))

ここでsqlの部分を

SELECT COUNT(fuga), MAX(fuga), MIN(fuga) FROM hoge;

のようにすると

AssertionError: Wrong number of items passed (3 vs 1)

というerrorが出ることがある.

これは

SELECT COUNT(fuga), MAX(fuga) AS max_value, MIN(fuga) AS min_value FROM hoge;

のように抽出後のcolumn名を指定すれば回避できる.

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
14