pandas.Series の構造と作成方法
pandas の Series オブジェクト は NumPy の一次元配列に明示的なインデクス (ラベル) をマップする(割り当てる)構造体です。pandas.Series() にシーケンスまたは配列を渡すと Series オブジェクトが生成されます。
# PANDAS_SERIES
# In[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
Series オブジェクトの左側の列に表示されている数字が Index オブジェクト とよばれる明示的インデクスで、index 属性にアクセスして取り出せます。
# In[2]
# dataのindex属性を取得
d_idx = data.index
print(d_idx)
RangeIndex(start=0, stop=3, step=1)
Series オブジェクトの右側の列に並ぶ数字は NumPy の配列 (ndarray) です。values 属性にアクセスして参照できます。
# In[3]
# dataのvalues属性を取得
d_val = data.values
print(d_val)
print(type(d_val))
[10 20 30] <class 'numpy.ndarray'>
Series のインデクス
Indexオブジェクトは NumPy 配列の内部インデクスとは別に定義されています。デフォルト設定では 0 から始まる整数がマップされていますが、ユーザーは index 引数にシーケンスや配列を渡してインデクスを自由に設定できます。Index オブジェクトは数値に限らず、文字列など任意の型で構成できます。
# PANDAS_SERIES_INDEX
# In[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オブジェクトの配列要素には、明示的なインデクスを使ってアクセスできます。
# In[2]
print(data["c"])
30
NumPy の配列と同様に、Seriesオブジェクトはスライシング、マスク、ファンシーインデクスなどの機能を備えています。
# In[3]
# インデクス b から d までスライシング
print(data["b" : "d"])
b 20 c 30 d 40 dtype: int64
# In[4]
# マスク(30以上の要素をすべて取得)
print(data[data >= 30])
c 30 d 40 e 50 dtype: int64
# In[5]
# ファンシーインデクス
idx = ["c", "b", "e"]
print(data[idx])
c 30 b 20 e 50 dtype: int64
Series とディクショナリの比較
Seriesオブジェクト は Python のディクショナリ (dictオブジェクト) に類似する構造体です。Indexオブジェクトはディクショナリの key、一次元配列はディクショナリの value と考えることができます。実際、pandas.Series() にディクショナリを渡すと そのままの形で Series オブジェクトに変換されます。
# PANDAS_SERIES_DICTIONARY
# In[1]
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オブジェクトを生成します。
# PANDAS_SERIES_SCALAR
# In[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 を加えます:
# In[2]
# すべての要素に5を加える
y = x + 5
print(y)
a 15 b 25 c 35 dtype: int64
2 * x はすべての要素を 2 倍します:
# In[3]
# すべての要素を2倍する
z = 2*x
print(z)
a 20 b 40 c 60 dtype: int64
Series とユニバーサル関数
NumPy のユニバーサル関数 (ufunc) に Seriesオブジェクトを渡すと、インデクスをそのまま残します。
# In[4]
# すべての要素の自然対数をとる
y = np.log(x)
print(y)
a 2.302585 b 2.995732 c 3.401197 dtype: float64
Series のデータ操作
NumPy配列と同じように、Seriesオブジェクト同士で算術演算子やメソッドを用いた演算が可能です。最初に簡単な例として、共通インデクスが割り当てられた Series 同士で足し算を実行してみます。
# PANDAS_SERIES_ADD
# In[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 のインデクスを逆順に定義し直します。
# In[2]
# xのインデクス順序を変更
x = pd.Series([10, 20, 30], index=list("BCA"))
print(x)
B 10 C 20 A 30 dtype: int64
改めて x に y を加えてみます。
# In[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 をあらためて次のように定義し直します。
# In[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 を加えると次のような結果となります。
# In[5]
# xにyを加える
print(x + y)
A NaN B 25.0 C 25.0 D NaN dtype: float64
インデクス "A" とインデクス "D" では、要求される演算が実行できないので「欠損値」として扱われ、NaN (Not a Number : 非数) で埋められています (欠損値については、こちらの記事で詳しく解説しています)。
しかし状況によっては、欠損値に NaN 以外を与えたいこともあります。たとえば、add()メソッドの引数 fill_value に 0 を渡すと、x と y にそれぞれ仮想的なインデクス "D" とインデクス "A" を付加して、要素 0 を割り当てて足し算できます。
# In[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() |
pandas.Seriesについて対話形式で説明します
pandas.Seriesについて、ChatGPT に対話形式で解説してもらいました。
生徒: 先生、pandasのSeriesについて教えてください。Seriesって何ですか?
先生: もちろんです。pandasのSeriesは、1次元のデータ構造であり、1つの列を表現するために使用されます。
生徒: なるほど、1次元のデータ構造で1つの列を表現するんですね。DataFrameとは違うんですか?
先生: そうです、DataFrameとは異なります。DataFrameは複数の列と行からなるテーブル形式のデータを扱いますが、Seriesは単一の列のデータを扱います。
生徒: なるほど、Seriesが1つの列のデータを表現するんですね。具体的な例を教えていただけますか?
先生: もちろんです。例えば、以下のような名前のSeriesを考えましょう。
◆◆◆◆◆
0 太郎
1 花子
2 健太
◆◆◆◆◆
この場合、0、1、2がインデックスと呼ばれるラベルで付けられた値(名前)を表しています。
生徒: インデックスというのは、行のラベルのことですか?
先生: その通りです。Seriesは値の配列にインデックスを付けることで、個々の要素にラベルを持たせることができます。このラベルはデータに対して意味を持たせたり、特定の要素にアクセスする際に便利です。
生徒: なるほど、ラベルを付けてデータを管理することができるんですね。Seriesではどのような操作ができるんですか?
先生: Seriesでは、インデックスを使って要素の選択やフィルタリング、演算などが行えます。また、Seriesには組み込みのメソッドや関数を使ってデータの集計や統計処理も行うことができます。
生徒: なるほど、インデックスを使って要素の操作や統計処理ができるんですね。
先生: 正解です。Seriesは単一の列のデータを効果的に扱うためのデータ構造です。DataFrameと併用することで、より複雑なデータ操作や分析が可能になります。
生徒: 分かりました!Seriesは列のデータを扱うための便利な構造なんですね。ありがとうございます!