[pandas] Seriesオブジェクト

[pandas] Seriesオブジェクト

Series

 pandas の Seriesオブジェクト は NumPy の一次元配列に明示的なインデクス (ラベル) をマップする構造体です。pandas.Series() にシーケンスまたは配列を渡すと Seriesオブジェクトが生成されます。

# リストPD01-1

# NumPyとpandasをインポート
import numpy as np
import pandas as pd

# Seriesオブジェクトを生成
data = pd.Series([10, 20, 30])

print(data)
0    10
1    20
2    30
dtype: int64

 左側の列に表示されている数字が Indexオブジェクト (明示的なインデクス) であり、index 属性にアクセスして取り出すことができます。

# リストPD01-2

# dataのindex属性を取得
d_idx = data.index

print(d_idx)
RangeIndex(start=0, stop=3, step=1)

 右側の列に並ぶ数字は NumPy の配列 (ndarray) で、values 属性にアクセスして取り出せます。

# リストPD01-3

# dataのvalues属性を取得
d_val = data.values

print(d_val)
print(type(d_val))
[10 20 30]
<class 'numpy.ndarray'>

明示的なインデクス

 Indexオブジェクトは NumPy 配列の内部インデクスとは別に定義されています。デフォルト設定では 0 から始まる整数がマップされていますが、ユーザーは index 引数にシーケンスや配列を渡してインデクスを自由に設定できます。Indexオブジェクトは数値に限らず、文字列など任意の型で構成できます。

# リストPD02-1

# 配列に文字列をマップする
data = pd.Series([10, 20, 30, 40, 50],
                 index = ["a", "b", "c", "d", "e"])

print(data)
a    10
b    20
c    30
d    40
e    50
dtype: int64

 Seriesオブジェクトの配列要素には、明示的なインデクスを使ってアクセスできます。

# リストPD02-2

print(data["c"])
30

 NumPy の配列と同様に、Seriesオブジェクトはスライシング、マスク、ファンシーインデクスなどの機能を備えています。

# リストPD02-3

# インデクス b から d までスライシング
print(data["b" : "d"])
b    20
c    30
d    40
dtype: int64
# リストPD02-4

# マスク(30以上の要素をすべて取得)
print(data[data >= 30])
c    30
d    40
e    50
dtype: int64
# リストPD02-5

# ファンシーインデクス
idx = ["c", "b", "e"]
print(data[idx])
c    30
b    20
e    50
dtype: int64

ディクショナリとの比較

 Seriesオブジェクト は Python のディクショナリ (dictオブジェクト) に類似する構造体です。Indexオブジェクトはディクショナリの key、一次元配列はディクショナリの value と考えることができます。実際、pandas.Series() にディクショナリを渡すと Seriesオブジェクトに変換されます。

# リストPD03

# NumPyとpandas をインポート
import numpy as np
import pandas as pd

# Python入門書の表題と価格
python_book_dict = {"かんたんPython" : 3002,
                    "Pythonスタートブック" : 2700,
                    "わかるPython" : 2570}

# 辞書をSeriesオブジェクトに変換
python_book = pd.Series(python_book_dict)

print(python_book)
かんたんPython       3002
Pythonスタートブック    2700
わかるPython        2570
dtype: int64

Seriesとスカラーの演算

 算術演算子を使って Seriesオブジェクトとスカラー (数値) の間で演算を実行すると、オブジェクトの中に組み込まれた NumPy の一次元配列とスカラーの間で演算が実行され、インデクスはそのまま保存されます。簡単な例を見てみましょう。最初に次のような Seriesオブジェクトを生成します。

# リストPD04-1

# NumPyとpandas をインポート
import numpy as np
import pandas as pd

# Seriesオブジェクトを生成
x = pd.Series([10, 20, 30],
              index = ["a", "b", "c"])

print(x)
a    10
b    20
c    30
dtype: int64

 x + 5 は、すべての要素に 5 を加えます:

# リストPD04-2

# すべての要素に5を加える
y = x + 5

print(y)
a    15
b    25
c    35
dtype: int64

 2 * x はすべての要素を 2 倍します:

# リストPD04-3

# すべての要素を2倍する
z = 2*x 

print(z)
a    20
b    40
c    60
dtype: int64

Seriesとufunc

 NumPy のユニバーサル関数 (ufunc) に Seriesオブジェクトを渡すとインデクスをそのまま残します。リストPD04-1 で生成した Seriesオブジェクト x を使って確認してみます。

# リストPD04-4

# すべての要素の自然対数をとる
y = np.log(x)

print(y)
a    2.302585
b    2.995732
c    3.401197
dtype: float64

 

Seriesのデータ操作

 NumPy配列と同じように、Seriesオブジェクト同士で算術演算子やメソッドを用いた演算が可能です。最初に簡単な例として、共通インデクスが割り当てられた Series 同士で足し算を実行してみます。

# リストPD05-1

import numpy as np
import pandas as pd

# Seriesオブジェクトを生成
x = pd.Series([10, 20, 30], index=list("ABC"))
y = pd.Series([ 5, 10, 15], index=list("ABC"))

print(x + y)
A    15
B    30
C    45
dtype: int64

 今度は x のインデクスを逆順に定義し直します。

# リストPD05-2

# xのインデクス順序を変更
x = pd.Series([10, 20, 30], index=list("BCA"))

print(x)
B    10
C    20
A    30
dtype: int64

 改めて x に y を加えてみます。

# リストPD05-3

# Series x
# B    10
# C    20
# A    30
# dtype: int64

# Series y
# A     5
# B    10
# C    15
# dtype: int64

print(x + y)
A    35
B    20
C    35
dtype: int64

 結果を見ると、同じ明示的インデクスをもつ要素同士で足し算されていることがわかります。また、x + y のインデクスは A から順に整列しています。このように、Seriesオブジェクトは自動ソート機能を備えています。

 pandas はもっと複雑な演算にも対応しています。
 今度は互いに異なるインデクスを含む Series 同士の演算を試みます。x と y をあらためて次のように定義し直します。

# リストPD05-4

# Seriesオブジェクトを生成
x = pd.Series([10, 20, 30], index=list("CBA"))
y = pd.Series([ 5, 10, 15], index=list("BDC"))

print(x,"\n")
print(y)
C    10
B    20
A    30
dtype: int64 

B     5
D    10
C    15
dtype: int64

 x にはインデクス "D" の要素が含まれておらず、y にはインデクス "A" の要素が含まれていません。x と y を加えると次のような結果となります。

# リストPD05-5

# xにyを加える
print(x + y)
A     NaN
B    25.0
C    25.0
D     NaN
dtype: float64

 インデクス "A" とインデクス "D" では、要求される演算が実行できないので「欠損値」として扱われ、NaN (Not a Number : 非数) で埋められています (欠損値については別の記事で詳しく解説します)。

 [pandas] Series のインデクス整列01
 しかし状況によっては、欠損値に NaN 以外を与えたいこともあります。
 たとえば、add()メソッドの引数 fill_value に 0 を渡すと、x と y にそれぞれ仮想的なインデクス "D" とインデクス "A" を付加して、要素 0 を割り当てて足し算できます。

 [pandas] Series のインデクス整列02 fill_values

# リストPD05-6

# x に y を加える
# 仮想インデクス "A","D"に0を割り当てて演算を実行
z = x.add(y, fill_value=0)

print(z)
A    30.0
B    25.0
C    25.0
D    10.0
dtype: float64

 Seriesオブジェクトは、他にも以下のような算術メソッドを備えています。

演算の種類 算術メソッド
加算 add()
減算 sub()
乗算 mul()
除算 div()
切り捨て除算 floordiv()
剰余 mod()
べき乗 pow()