ホーム > python > pandas > pandas.DataFrame、pandas.Seriesの要素を置換する

pandas.DataFrame、pandas.Seriesの要素を置換する

pythonpandas

環境

今回動作の確認を行った際のバージョンは下記の通り
python:3.10.9
pandas:1.5.3
データセット:scikit-learnのirisを使用(scikit-learnは1.2.2)

データセットの準備

前回と同じirisデータセットを使用して動作を確認していきます。

from sklearn.datasets import load_iris
if __name__ == '__main__':
df = load_iris(as_frame=True).frame
print(df.head())
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 0 5.1 3.5 ... 0.2 0
# 1 4.9 3.0 ... 0.2 0
# 2 4.7 3.2 ... 0.2 0
# 3 4.6 3.1 ... 0.2 0
# 4 5.0 3.6 ... 0.2 0
# [5 rows x 5 columns]


replaceを使用した要素の置換

pandas.DataFrame、pandas.Seriesにはreplace()メソッドが用意されており、これを用いることで要素の置換を行うことが可能です。
pandas.Series.replace
pandas.DataFrame.replace

irisデータセットではtargetに0、1、2が設定されておりこれらはそれぞれsetosa、versicolor、virginicaを表しています。

from sklearn.datasets import load_iris
if __name__ == '__main__':
print(load_iris(as_frame=True).target_names)
# ['setosa' 'versicolor' 'virginica']

今回は0、1、2をsetosa、versicolor、virginicaに変換してみます。
replace()メソッドは
replace('元の値', '置換後の値')
で置換することが可能です。

from sklearn.datasets import load_iris
if __name__ == '__main__':
df = load_iris(as_frame=True).frame
# 最後の5行表示
print(df.tail())
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 145 6.7 3.0 ... 2.3 2
# 146 6.3 2.5 ... 1.9 2
# 147 6.5 3.0 ... 2.0 2
# 148 6.2 3.4 ... 2.3 2
# 149 5.9 3.0 ... 1.8 2
#
# [5 rows x 5 columns]
# 花の種類をリストで取得
target_name = load_iris(as_frame=True).target_names
# for文を使用して花の種類を順番に置換
for i, t in enumerate(target_name):
df = df.replace(i, t)
# 最後の5行表示
print(df.tail())
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 145 6.7 3.0 ... 2.3 virginica
# 146 6.3 2.5 ... 1.9 virginica
# 147 6.5 3.0 ... virginica virginica
# 148 6.2 3.4 ... 2.3 virginica
# 149 5.9 3.0 ... 1.8 virginica
#
# [5 rows x 5 columns]
# target列をSeriesとして抽出
s = df['target']
# for文を使用して花の種類を順番に置換
for i, t in enumerate(target_name):
s = s.replace(i, t)
# 最初の5行表示
print(s.head())
# 0 setosa
# 1 setosa
# 2 setosa
# 3 setosa
# 4 setosa
# Name: target, dtype: object
# 最後の5行表示
print(s.tail())
# 145 virginica
# 146 virginica
# 147 virginica
# 148 virginica
# 149 virginica
# Name: target, dtype: object

引数に{'元の値':'置換後の値'}の様な辞書型データを渡すことでも同様に置換が可能です。

from sklearn.datasets import load_iris
if __name__ == '__main__':
df = load_iris(as_frame=True).frame
# 最後の5行表示
print(df.tail())
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 145 6.7 3.0 ... 2.3 2
# 146 6.3 2.5 ... 1.9 2
# 147 6.5 3.0 ... 2.0 2
# 148 6.2 3.4 ... 2.3 2
# 149 5.9 3.0 ... 1.8 2
#
# [5 rows x 5 columns]
# 花の種類をリストで取得
target_name = load_iris(as_frame=True).target_names
print(df.replace({0:target_name[0], 1:target_name[1], 2:target_name[2]}).tail())
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 145 6.7 3.0 ... 2.3 virginica
# 146 6.3 2.5 ... 1.9 virginica
# 147 6.5 3.0 ... virginica virginica
# 148 6.2 3.4 ... 2.3 virginica
# 149 5.9 3.0 ... 1.8 virginica
#
# [5 rows x 5 columns]

しかしいずれの場合も上記の様に全列が置換対象となってしまいます。
{対象の列名:{'元の値':'置換後の値'}}という辞書型データを渡すことで特定の列のみを対象としてい置換することが可能です。

from sklearn.datasets import load_iris
if __name__ == '__main__':
df = load_iris(as_frame=True).frame
# 最後の5行表示
print(df.tail())
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 145 6.7 3.0 ... 2.3 2
# 146 6.3 2.5 ... 1.9 2
# 147 6.5 3.0 ... 2.0 2
# 148 6.2 3.4 ... 2.3 2
# 149 5.9 3.0 ... 1.8 2
#
# [5 rows x 5 columns]
# 花の種類をリストで取得
target_name = load_iris(as_frame=True).target_names
print(df.replace({'target':{0:target_name[0], 1:target_name[1], 2:target_name[2]}}).tail())
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 145 6.7 3.0 ... 2.3 virginica
# 146 6.3 2.5 ... 1.9 virginica
# 147 6.5 3.0 ... 2.0 virginica
# 148 6.2 3.4 ... 2.3 virginica
# 149 5.9 3.0 ... 1.8 virginica
#
# [5 rows x 5 columns]

また、pandas.Series.replacepandas.DataFrame.replaceには引数inplaceが用意されており、Trueを設定することで元のDataFrameをそのまま置換することが可能です。

from sklearn.datasets import load_iris
if __name__ == '__main__':
df = load_iris(as_frame=True).frame
# 最後の5行表示
print(df.tail())
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 145 6.7 3.0 ... 2.3 2
# 146 6.3 2.5 ... 1.9 2
# 147 6.5 3.0 ... 2.0 2
# 148 6.2 3.4 ... 2.3 2
# 149 5.9 3.0 ... 1.8 2
#
# [5 rows x 5 columns]
# 花の種類をリストで取得
target_name = load_iris(as_frame=True).target_names
# inplaceがFalse(デフォルト値)の場合
df.replace({'target': {0: target_name[0], 1: target_name[1], 2: target_name[2]}})
print(df)
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 0 5.1 3.5 ... 0.2 0
# 1 4.9 3.0 ... 0.2 0
# 2 4.7 3.2 ... 0.2 0
# 3 4.6 3.1 ... 0.2 0
# 4 5.0 3.6 ... 0.2 0
# .. ... ... ... ... ...
# 145 6.7 3.0 ... 2.3 2
# 146 6.3 2.5 ... 1.9 2
# 147 6.5 3.0 ... 2.0 2
# 148 6.2 3.4 ... 2.3 2
# 149 5.9 3.0 ... 1.8 2
# [150 rows x 5 columns]
# inplaceがTrueの場合
df.replace({'target': {0: target_name[0], 1: target_name[1], 2: target_name[2]}}, inplace=True)
print(df)
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 0 5.1 3.5 ... 0.2 0
# 1 4.9 3.0 ... 0.2 0
# 2 4.7 3.2 ... 0.2 0
# 3 4.6 3.1 ... 0.2 0
# 4 5.0 3.6 ... 0.2 0
# .. ... ... ... ... ...
# 145 6.7 3.0 ... 2.3 2
# 146 6.3 2.5 ... 1.9 2
# 147 6.5 3.0 ... 2.0 2
# 148 6.2 3.4 ... 2.3 2
# 149 5.9 3.0 ... 1.8 2
# [150 rows x 5 columns]


正規表現を使って置換

pandas.Series.replace
pandas.DataFrame.replaceには引数regexが用意されており、Trueを設定することで正規表現を使用した置換が可能となります。
replaceは完全一致した値しか置換されないため正規表現を使用しない場合、例えば下記の様に置換が行われません。

from sklearn.datasets import load_iris
if __name__ == '__main__':
df = load_iris(as_frame=True).frame
# 花の種類をリストで取得
target_name = load_iris(as_frame=True).target_names
df.replace({'target': {0: target_name[0], 1: target_name[1], 2: target_name[2]}}, inplace=True)
print(df)
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 0 5.1 3.5 ... 0.2 setosa
# 1 4.9 3.0 ... 0.2 setosa
# 2 4.7 3.2 ... 0.2 setosa
# 3 4.6 3.1 ... 0.2 setosa
# 4 5.0 3.6 ... 0.2 setosa
# .. ... ... ... ... ...
# 145 6.7 3.0 ... 2.3 virginica
# 146 6.3 2.5 ... 1.9 virginica
# 147 6.5 3.0 ... 2.0 virginica
# 148 6.2 3.4 ... 2.3 virginica
# 149 5.9 3.0 ... 1.8 virginica
# [150 rows x 5 columns]
print(df.replace({'target':{'set':'SET'}}))
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 0 5.1 3.5 ... 0.2 setosa
# 1 4.9 3.0 ... 0.2 setosa
# 2 4.7 3.2 ... 0.2 setosa
# 3 4.6 3.1 ... 0.2 setosa
# 4 5.0 3.6 ... 0.2 setosa
# .. ... ... ... ... ...
# 145 6.7 3.0 ... 2.3 virginica
# 146 6.3 2.5 ... 1.9 virginica
# 147 6.5 3.0 ... 2.0 virginica
# 148 6.2 3.4 ... 2.3 virginica
# 149 5.9 3.0 ... 1.8 virginica
# [150 rows x 5 columns]

正規表現を使うと部分的な置換も可能です。試しに「t(任意の文字列)s」を「TTT」に変換するという処理を実行してみると下記の様になります。

from sklearn.datasets import load_iris
if __name__ == '__main__':
df = load_iris(as_frame=True).frame
# 花の種類をリストで取得
target_name = load_iris(as_frame=True).target_names
df.replace({'target': {0: target_name[0], 1: target_name[1], 2: target_name[2]}}, inplace=True)
print(df)
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 0 5.1 3.5 ... 0.2 setosa
# 1 4.9 3.0 ... 0.2 setosa
# 2 4.7 3.2 ... 0.2 setosa
# 3 4.6 3.1 ... 0.2 setosa
# 4 5.0 3.6 ... 0.2 setosa
# .. ... ... ... ... ...
# 145 6.7 3.0 ... 2.3 virginica
# 146 6.3 2.5 ... 1.9 virginica
# 147 6.5 3.0 ... 2.0 virginica
# 148 6.2 3.4 ... 2.3 virginica
# 149 5.9 3.0 ... 1.8 virginica
# [150 rows x 5 columns]
print(df.replace('t.s', 'TTT', regex = True).head())
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 0 5.1 3.5 ... 0.2 seTTTa
# 1 4.9 3.0 ... 0.2 seTTTa
# 2 4.7 3.2 ... 0.2 seTTTa
# 3 4.6 3.1 ... 0.2 seTTTa
# 4 5.0 3.6 ... 0.2 seTTTa
# .. ... ... ... ... ...
# 145 6.7 3.0 ... 2.3 virginica
# 146 6.3 2.5 ... 1.9 virginica
# 147 6.5 3.0 ... 2.0 virginica
# 148 6.2 3.4 ... 2.3 virginica
# 149 5.9 3.0 ... 1.8 virginica
# [150 rows x 5 columns]


Nanの置換

実データにおいて欠損値が含まれているケースは多々あります。そのような場合はreplace()を使わずpandas.DataFrame.fillnaを使用することで簡単に欠損値を変換することが出来ます。
irisデータセットにはNanが含まれていないため、意図的にデータを変換の上fillnaを実行してみます。
特定の値をnp.nanへ置換すればOKです。

from sklearn.datasets import load_iris
if __name__ == '__main__':
df = load_iris(as_frame=True).frame
# 3.0をNanへ置換
df.replace(3.0, np.nan, inplace=True)
# 0.2をNanへ置換
df.replace(0.2, np.nan, inplace=True)
print(df)
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 0 5.1 3.5 ... NaN 0
# 1 4.9 NaN ... NaN 0
# 2 4.7 3.2 ... NaN 0
# 3 4.6 3.1 ... NaN 0
# 4 5.0 3.6 ... NaN 0
# .. ... ... ... ... ...
# 145 6.7 NaN ... 2.3 2
# 146 6.3 2.5 ... 1.9 2
# 147 6.5 NaN ... 2.0 2
# 148 6.2 3.4 ... 2.3 2
# 149 5.9 NaN ... 1.8 2
# [150 rows x 5 columns]
# Nanを1.0へ置換(穴埋め)
df.fillna(1.0, inplace=True)
print(df)
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 0 5.1 3.5 ... 1.0 0
# 1 4.9 1.0 ... 1.0 0
# 2 4.7 3.2 ... 1.0 0
# 3 4.6 3.1 ... 1.0 0
# 4 5.0 3.6 ... 1.0 0
# .. ... ... ... ... ...
# 145 6.7 1.0 ... 2.3 2
# 146 6.3 2.5 ... 1.9 2
# 147 6.5 1.0 ... 2.0 2
# 148 6.2 3.4 ... 2.3 2
# 149 5.9 1.0 ... 1.8 2
# [150 rows x 5 columns]