Pandas入門(下)

Pandas

Pandas入門編の続きです。
公式ページ 10 minutes to pandasの流れに沿って学習していきます。
コンテンツOperationsからになります。

オブジェクトの操作

統計値

a = pd.Series([1, 2, 3, 4, 5, 6])
print('a = \n', a)

b = np.array(
    [
        [1, 2, 3, 4, 5, 6], 
        [7, 8, 9, 10, 11, 12], 
        [13, 14, 15, 16, 17, 18],
        [19, 20, 21, 22, 23, 24],
        [25, 26, 27, 28, 29, 30],
        [31, 32, 33, 34, 35, 36], 
    ]
)

c = pd.DataFrame(
    b, 
    index = a, 
    columns=list('ABCDEF'),
) 
print('c = \n', c) 

print(c.mean()) 
print(c.mean(1))

s = pd.Series(
    [1, 3, 5, np.nan, 6, 8],
    index=a
).shift(2)
print('s = \n', s)

print(c.sub(s, axis='index')
出力
a = 
 0    1
1    2
2    3
3    4
4    5
5    6
dtype: int64

c = 
     A   B   C   D   E   F
1   1   2   3   4   5   6
2   7   8   9  10  11  12
3  13  14  15  16  17  18
4  19  20  21  22  23  24
5  25  26  27  28  29  30
6  31  32  33  34  35  36

A    16.0
B    17.0
C    18.0
D    19.0
E    20.0
F    21.0
dtype: float64

1     3.5
2     9.5
3    15.5
4    21.5
5    27.5
6    33.5
dtype: float64

s = 
 1    NaN
2    NaN
3    1.0
4    3.0
5    5.0
6    NaN
dtype: float64

      A     B     C     D     E     F
1   NaN   NaN   NaN   NaN   NaN   NaN
2   NaN   NaN   NaN   NaN   NaN   NaN
3  12.0  13.0  14.0  15.0  16.0  17.0
4  16.0  17.0  18.0  19.0  20.0  21.0
5  20.0  21.0  22.0  23.0  24.0  25.0
6   NaN   NaN   NaN   NaN   NaN   NaN

mean()で列平均、mean(1)で行平均が取得できます。
shift()で、要素をずらしています。
sub()で、2つのオブジェクトの差分を取っています。
行番号の対応する部分ごとに差を計算しています。
差を取るオブジェクトの要素どちらかがNaNの部分は、結果がNaNになります。

関数を適用する

print(c.apply(np.cumsum))
print(c.apply(lambda x: x.max() - x.min()))
print(c.apply(lambda x: x.max() - x.min(), axis=1))
出力
    A    B    C    D    E    F
1   1    2    3    4    5    6
2   8   10   12   14   16   18
3  21   24   27   30   33   36
4  40   44   48   52   56   60
5  65   70   75   80   85   90
6  96  102  108  114  120  126

A    30
B    30
C    30
D    30
E    30
F    30
dtype: int64

1    5
2    5
3    5
4    5
5    5
6    5
dtype: int64

np.cumsum()は、自身の要素と一つ前の要素を足し合わせます。

ヒストグラム

s = pd.Series(
    np.random.randint( 0, 7, size = 10)
)  
print('s = \n', s)
print('s.value_counts() = \n', s.value_counts())
出力
s = 
 0    0
1    3
2    6
3    4
4    6
5    0
6    2
7    4
8    3
9    4
dtype: int64

s.value_counts() = 
 4    3
6    2
3    2
0    2
2    1
dtype: int64

value_counts()で、値ごとの要素の個数を数え上げることができます。出力結果は、個数が多い順になっています。

文字列オブジェクトの操作

s = pd.Series(
    [
        'A', 'B', 'C', 'Abc', 'aBc', 'abC', 'ABC', np.NaN, 'abc'
    ]
)
print('s = \n', s)
print('s.str.lower = \n', s.str.lower())
出力
s = 
 0      A
1      B
2      C
3    Abc
4    aBc
5    abC
6    ABC
7    NaN
8    abc
dtype: object

s.str.lower() = 
 0      a
1      b
2      c
3    abc
4    abc
5    abc
6    abc
7    NaN
8    abc
dtype: object

s.str.upper() = 
 0      A
1      B
2      C
3    ABC
4    ABC
5    ABC
6    ABC
7    NaN
8    ABC
dtype: object

s.str.len() = 
 0    1.0
1    1.0
2    1.0
3    3.0
4    3.0
5    3.0
6    3.0
7    NaN
8    3.0
dtype: float64

str.lower()で、各要素の文字列をすべて小文字へ変換してくれます。同様に、str.upper()は大文字へ変換します。
str.len()では、各要素の文字列長を取得しています。

オブジェクトの結合

a = pd.DataFrame(
    np.random.randn(10, 4)
)
print('a = \n', a)

b = [
    a[:3], a[3:7], a[7:]
]
print('b = \n', b)

print('pd.concat(b) = \n', pd.concat(b))
出力
a = 
           0         1         2         3
0  0.927622 -1.061252  1.219412  1.366575
1  1.187424  0.817243 -0.935146  0.420047
2 -0.365770  0.355189 -1.045944  1.245309
3 -0.730509  0.252370 -0.884084 -0.953155
4 -0.211724  2.837807 -0.663538 -0.114342
5  0.228473  1.206067 -0.292555  1.003695
6  0.403963 -1.236015  2.391796 -0.821328
7  0.436652 -1.092702  0.714237 -0.217711
8  0.366864  0.513808 -1.047558  1.947990
9  1.354420 -0.512573  0.414785  1.190989

b = 
 [          0         1         2         3
0  0.927622 -1.061252  1.219412  1.366575
1  1.187424  0.817243 -0.935146  0.420047
2 -0.365770  0.355189 -1.045944  1.245309,           0         1         2         3
3 -0.730509  0.252370 -0.884084 -0.953155
4 -0.211724  2.837807 -0.663538 -0.114342
5  0.228473  1.206067 -0.292555  1.003695
6  0.403963 -1.236015  2.391796 -0.821328,           0         1         2         3
7  0.436652 -1.092702  0.714237 -0.217711
8  0.366864  0.513808 -1.047558  1.947990
9  1.354420 -0.512573  0.414785  1.190989]

pd.concat(b) = 
           0         1         2         3
0  0.927622 -1.061252  1.219412  1.366575
1  1.187424  0.817243 -0.935146  0.420047
2 -0.365770  0.355189 -1.045944  1.245309
3 -0.730509  0.252370 -0.884084 -0.953155
4 -0.211724  2.837807 -0.663538 -0.114342
5  0.228473  1.206067 -0.292555  1.003695
6  0.403963 -1.236015  2.391796 -0.821328
7  0.436652 -1.092702  0.714237 -0.217711
8  0.366864  0.513808 -1.047558  1.947990
9  1.354420 -0.512573  0.414785  1.190989

オブジェクトを3つに分割して、最後に、pd.concat()を使用して結合しています。
aオブジェクトと結合後のbオブジェクトは同じですね。

left = pd.DataFrame(
    {
        'key': ['foo', 'foo'],
        'lval': [1, 2]
    }
)
print('left = \n', left)

right = pd.DataFrame(
    {
        'key': ['foo', 'foo'],
        'rval': [4, 5]
    }
)
print('right = \n', right)

print("pd.merge(left, right, on='key') = \n", pd.merge(left, right, on='key'))

left = pd.DataFrame(
    {
        'key': ['foo', 'bar'],
        'lval': [1, 2]
    }
)
print('left = \n', left)

right = pd.DataFrame(
    {
        'key': ['foo', 'bar'],
        'rval': [4, 5]
    }
)
print('right = \n', right)

print("pd.merge(left, right, on='key') = \n", pd.merge(left, right, on='key'))
出力
left = 
    key  lval
0  foo     1
1  foo     2

right = 
    key  rval
0  foo     4
1  foo     5

pd.merge(left, right, on='key') = 
    key  lval  rval
0  foo     1     4
1  foo     1     5
2  foo     2     4
3  foo     2     5

left = 
    key  lval
0  foo     1
1  bar     2

right = 
    key  rval
0  foo     4
1  bar     5

pd.merge(left, right, on='key') = 
    key  lval  rval
0  foo     1     4
1  bar     2     5

pd.perge()を利用すると、指定した項目の値が一致するもの通しで結合することができます。
SQLで、outer join(外部結合)を使うような感じですね。

グルーピング

a = pd.DataFrame(
    {
        'A': [
            'foo', 'bar', 'foo', 'bar', 'foo', 'bar', 'foo', 'bar'
        ],
        'B': [
            'one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'
        ],
        'C': np.random.randn(8),
        'D': np.random.randn(8)
    }
)
print('a = \n', a)

print("a.groupby('A').sum() = \n", a.groupby('A').sum())
print("a.groupby(['A', 'B']).sum() = \n", a.groupby(['A', 'B']).sum())
print("a.groupby(['A', 'B']).count() = \n", a.groupby(['A', 'B']).count())
出力
a = 
      A      B         C         D
0  foo    one  0.548487  0.092763
1  bar    one  0.664254 -1.525959
2  foo    two -1.501490 -2.262083
3  bar  three  0.017315 -0.502200
4  foo    two -0.137222 -0.403101
5  bar    two -0.562191  0.526629
6  foo    one  0.698066 -2.220822
7  bar  three -0.291728 -0.957708

a.groupby('A').sum() = 
             C         D
A                      
bar -0.172349 -2.459239
foo -0.392158 -4.793242

a.groupby(['A', 'B']).sum() = 
                   C         D
A   B                        
bar one    0.664254 -1.525959
    three -0.274413 -1.459908
    two   -0.562191  0.526629
foo one    1.246553 -2.128059
    two   -1.638711 -2.665183

a.groupby(['A', 'B']).count() = 
            C  D
A   B          
bar one    1  1
    three  2  2
    two    1  1
foo one    2  2
    two    2  2

groupby()を使って、同じ値ごとにグルーピングしています。
続けてsum()を実行することで、グループごとの合計値を取得しています。
sum()の代わりにcount()を使えば、要素の個数が取得できます。

変形

a = list(
    zip(
        *[
            ['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
            ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']
        ]
    )
)
print('a = \n', a)

index = pd.MultiIndex.from_tuples(
    a,
    names = ['first', 'second']
)
print('index = \n', index)

b = pd.DataFrame(
    np.random.randn(8, 2),
    index=index,
    columns = ['A', 'B']
)
print('b = \n', b)

c = b[:4]
print('c = \n', c)
出力
a = 
 [('bar', 'one'), ('bar', 'two'), ('baz', 'one'), ('baz', 'two'), ('foo', 'one'), ('foo', 'two'), ('qux', 'one'), ('qux', 'two')]

index = 
 MultiIndex([('bar', 'one'),
            ('bar', 'two'),
            ('baz', 'one'),
            ('baz', 'two'),
            ('foo', 'one'),
            ('foo', 'two'),
            ('qux', 'one'),
            ('qux', 'two')],
           names=['first', 'second'])

b = 
                      A         B
first second                    
bar   one     0.201214 -0.420626
      two    -0.121557  1.066747
baz   one     0.898504 -0.779243
      two    -0.081244 -1.894931
foo   one    -1.136553 -0.223014
      two    -2.159590  0.631377
qux   one     0.467664 -1.403018
      two    -0.539614  0.146575

c = 
                      A         B
first second                    
bar   one     0.201214 -0.420626
      two    -0.121557  1.066747
baz   one     0.898504 -0.779243
      two    -0.081244 -1.894931

まず、元になるオブジェクトを作成します。
zip()では、与えられた引数のリストから要素を順番に取り出してペアを作成しています。
zip()の引数の先頭についている*(アスタリスク)は、アンパックと呼ばれるものです。
与えられたリストやタブルを分解する作用があります。

次によくわからないのが、pd.MultiIndexです。
その名と通りで、インデックスが多重階層になっているものです。
Excelでピボットを扱う際などによく出てくると思います。

今回のケースだと、first、secondインデックスの中に更にbar、bazとone、twoがあり複合インデックスになっています。

d = c.stack()
print('d = \n', d)

e = d.unstack()
print('e = \n', e)

f = c.unstack(1)
print('f = \n', f)

g = c.unstack(0)
print('g = \n', g)
出力
d = 
 first  second   
bar    one     A   -1.052659
               B   -0.340091
       two     A    1.680716
               B   -0.479246
baz    one     A   -0.930143
               B    1.774671
       two     A   -2.045746
               B   -0.830786
dtype: float64

e = 
                      A         B
first second                    
bar   one    -1.052659 -0.340091
      two     1.680716 -0.479246
baz   one    -0.930143  1.774671
      two    -2.045746 -0.830786

f = 
                A                   B          
second       one       two       one       two
first                                         
bar    -1.052659  1.680716 -0.340091 -0.479246
baz    -0.930143 -2.045746  1.774671 -0.830786

g = 
                A                   B          
first        bar       baz       bar       baz
second                                        
one    -1.052659 -0.930143 -0.340091  1.774671
two     1.680716 -2.045746 -0.479246 -0.830786

stack()を呼び出すと、列ごとに並んでいた要素が、行に積み上げられています。
unstack()で、逆の動きが起こります。
unstack()は、通常、最下層の項目が列へ並び替えられますが、引数で列へ並び替える階層を指定することもできます。

ピボット

a = pd.DataFrame(
    {
        'A': ['one', 'one', 'two', 'three'] * 3,
        'B': ['A', 'B', 'C'] * 4,
        'C': ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] * 2,
        'D': np.random.randn(12),
        'E': np.random.randn(12)
    }
)
print('a = \n', a)

print(pd.pivot_table(
    a,
    values='D',
    index=['A', 'B'],
    columns=['C']
))

print(pd.pivot_table(
    a,
    values=['D', 'E'], 
    index=['A', 'B'],
    columns=['C']
))
出力
a = 
         A  B    C         D         E
0     one  A  foo  0.245156 -0.044922
1     one  B  foo  0.779745  0.884248
2     two  C  foo -0.118581 -0.264967
3   three  A  bar  0.900290  1.187819
4     one  B  bar -0.383582  0.964441
5     one  C  bar -0.026941  0.235163
6     two  A  foo -1.112834 -0.479546
7   three  B  foo -0.315244 -0.110965
8     one  C  foo -1.033622  0.950809
9     one  A  bar  0.475349  1.364452
10    two  B  bar -2.455635 -1.507615
11  three  C  bar -0.957291 -1.068828

C             bar       foo
A     B                    
one   A  0.475349  0.245156
      B -0.383582  0.779745
      C -0.026941 -1.033622
three A  0.900290       NaN
      B       NaN -0.315244
      C -0.957291       NaN
two   A       NaN -1.112834
      B -2.455635       NaN
      C       NaN -0.118581

                D                   E          
C             bar       foo       bar       foo
A     B                                        
one   A  0.475349  0.245156  1.364452 -0.044922
      B -0.383582  0.779745  0.964441  0.884248
      C -0.026941 -1.033622  0.235163  0.950809
three A  0.900290       NaN  1.187819       NaN
      B       NaN -0.315244       NaN -0.110965
      C -0.957291       NaN -1.068828       NaN
two   A       NaN -1.112834       NaN -0.479546
      B -2.455635       NaN -1.507615       NaN
      C       NaN -0.118581       NaN -0.264967

日時オブジェクト

rng = pd.date_range('2020/6/1', periods=10, freq='S')
print('rng = \n', rng)

ts = pd.Series(
    np.random.randint(0, 50, len(rng)),
    index=rng
)
print('ts = \n', ts)

a = ts.resample('2S').sum()
print('a = \n', a)
出力
rng = 
 DatetimeIndex(['2020-06-01 00:00:00', '2020-06-01 00:00:01',
               '2020-06-01 00:00:02', '2020-06-01 00:00:03',
               '2020-06-01 00:00:04', '2020-06-01 00:00:05',
               '2020-06-01 00:00:06', '2020-06-01 00:00:07',
               '2020-06-01 00:00:08', '2020-06-01 00:00:09'],
              dtype='datetime64[ns]', freq='S')

ts = 
 2020-06-01 00:00:00    16
2020-06-01 00:00:01     6
2020-06-01 00:00:02    41
2020-06-01 00:00:03    25
2020-06-01 00:00:04    18
2020-06-01 00:00:05    27
2020-06-01 00:00:06     1
2020-06-01 00:00:07    44
2020-06-01 00:00:08    27
2020-06-01 00:00:09    39
Freq: S, dtype: int64

a = 
 2020-06-01 00:00:00    22
2020-06-01 00:00:02    66
2020-06-01 00:00:04    45
2020-06-01 00:00:06    45
2020-06-01 00:00:08    66
Freq: 2S, dtype: int64

pd.date_range()で日時配列を作成できます。
第1引数が初期日時、freq引数で単位、periods引数で期間を指定します。

resample()で、一定期間ごとの集計を出すことが可能です。
上の例では、2秒間隔ごとの値の合計を取っています。

カテゴリー

a = pd.DataFrame(
    {
        'id': [1, 2, 3, 4, 5, 6],
        'raw_grade': ['a', 'b', 'b', 'a', 'a', 'e']
    }
)
print('a = \n', a)

b = a['raw_grade'].astype('category')
print('b = \n', b)

b.cat.categories = [
    'very good',
    'good',
    'very bad'
]
print('b = \n', b)

a['grade'] = b
print('a = \n', a)
出力
a = 
    id raw_grade
0   1         a
1   2         b
2   3         b
3   4         a
4   5         a
5   6         e

b = 
 0    a
1    b
2    b
3    a
4    a
5    e
Name: raw_grade, dtype: category
Categories (3, object): [a, b, e]

b = 
 0    very good
1         good
2         good
3    very good
4    very good
5     very bad
Name: raw_grade, dtype: category
Categories (3, object): [very good, good, very bad]

a = 
    id raw_grade      grade
0   1         a  very good
1   2         b       good
2   3         b       good
3   4         a  very good
4   5         a  very good
5   6         e   very bad

b変数には、aオブジェクトの’raw_grade’列の値をカテゴリー型に変換した値を入ります。
出力結果のところに、
Categories (3, object): [a, b, e]
が表示されていますね。

さらに、カテゴリー型のカテゴリー値へアクセスするにはcatプロパティを使用します。
b.cat.bategoriesで、カテゴリーの値に新たな名前をつけています。

Pandasの一通りの機能をざっと眺めてきました。
さらに、解析した結果をmatplotlibで視覚化することもできます。
これについては、別で触れたいと思います。

コメント

タイトルとURLをコピーしました