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で視覚化することもできます。
これについては、別で触れたいと思います。
コメント