pandas.DataFrameの複数の列の文字列を結合して新たな列を生成
pandas.DataFrame
の複数の列の文字列を結合(連結)して新たな列を生成する方法について、以下の内容を説明する。
- 文字列の列同士の結合(連結)
str.cat()
+
演算子- 欠損値
NaN
の処理
- 文字列の列と数値の列の結合(連結)
- 連結した列を
pandas.DataFrame
に追加
例として、以下のデータを使用する。
import pandas as pd
df = pd.read_csv('data/src/sample_pandas_normal.csv').head(3)
print(df)
# name age state point
# 0 Alice 24 NY 64
# 1 Bob 42 CA 92
# 2 Charlie 18 CA 70
サンプルのcsvファイルはコチラ。
文字列の列同士の結合(連結)
str.cat()
文字列メソッドstr.cat()
で文字列の連結が可能。
呼び出し元のpandas.Series
と第一引数に指定したpandas.Series
の要素が連結されたpandas.Series
が返される。
print(df['name'].str.cat(df['state']))
# 0 AliceNY
# 1 BobCA
# 2 CharlieCA
# Name: name, dtype: object
引数sep
に文字列を指定すると間に挿入される。
print(df['name'].str.cat(df['state'], sep=' in '))
# 0 Alice in NY
# 1 Bob in CA
# 2 Charlie in CA
# Name: name, dtype: object
第一引数に指定するのは要素数が同じNumPy配列ndarray
やリストでもよい。
print(df['name'].str.cat(['X', 'Y', 'Z'], sep=' in '))
# 0 Alice in X
# 1 Bob in Y
# 2 Charlie in Z
# Name: name, dtype: object
また、第一引数にpandas.Series
やリストなどを要素とするリストを指定して複数の文字列を連結することも可能。
print(df['name'].str.cat([df['state'], ['X', 'Y', 'Z']], sep='-'))
# 0 Alice-NY-X
# 1 Bob-CA-Y
# 2 Charlie-CA-Z
# Name: name, dtype: object
第一引数に指定できるのはpandas.Series
やリストあるいはそれらのリストで、文字列を単独で指定するとエラー。
# print(df['name'].str.cat('X', sep='-'))
# ValueError: Did you mean to supply a `sep` keyword?
+演算子
単純に+
演算子を使ってもOK。こちらのほうが直感的かもしれない。
print(df['name'] + df['state'])
# 0 AliceNY
# 1 BobCA
# 2 CharlieCA
# dtype: object
すべての要素に同じ文字列を連結できる。
print(df['name'] + ' in ' + df['state'])
# 0 Alice in NY
# 1 Bob in CA
# 2 Charlie in CA
# dtype: object
要素数が同じNumPy配列ndarray
やリストの連結も可能。
print(df['name'] + ' in ' + df['state'] + ' - ' + ['X', 'Y', 'Z'])
# 0 Alice in NY - X
# 1 Bob in CA - Y
# 2 Charlie in CA - Z
# dtype: object
欠損値NaNの処理
欠損値NaN
が含まれる場合。説明のため、欠損値を含む列を追加する。
df['col_NaN'] = ['X', pd.np.nan, 'Z']
print(df)
# name age state point col_NaN
# 0 Alice 24 NY 64 X
# 1 Bob 42 CA 92 NaN
# 2 Charlie 18 CA 70 Z
str.cat()
では、デフォルトでは欠損値NaN
が含まれる要素は欠損値NaN
となる。
print(df['name'].str.cat(df['col_NaN'], sep='-'))
# 0 Alice-X
# 1 NaN
# 2 Charlie-Z
# Name: name, dtype: object
引数na_rep
で指定した文字列に置換できる。
print(df['name'].str.cat(df['col_NaN'], sep='-', na_rep='No Data'))
# 0 Alice-X
# 1 Bob-No Data
# 2 Charlie-Z
# Name: name, dtype: object
+
演算子を使う場合も欠損値NaN
が含まれる要素は欠損値NaN
となる。
print(df['name'] + '-' + df['col_NaN'])
# 0 Alice-X
# 1 NaN
# 2 Charlie-Z
# dtype: object
欠損値NaN
を任意の値に置換したい場合はfillna()
を使う。
print(df['name'] + '-' + df['col_NaN'].fillna('No Data'))
# 0 Alice-X
# 1 Bob-No Data
# 2 Charlie-Z
# dtype: object
文字列の列と数値の列の結合(連結)
文字列の列と数値の列を結合する場合は、数値の列をastype()
メソッドで文字列型str
に型変換する必要がある。
# print(df['name'].str.cat(df['age'], sep='-'))
# TypeError: sequence item 1: expected str instance, int found
print(df['name'].str.cat(df['age'].astype(str), sep='-'))
# 0 Alice-24
# 1 Bob-42
# 2 Charlie-18
# Name: name, dtype: object
+
演算子でも同様。
# print(df['name'] + '-' + df['age'])
# TypeError: can only concatenate str (not "int") to str
print(df['name'] + '-' + df['age'].astype(str))
# 0 Alice-24
# 1 Bob-42
# 2 Charlie-18
# dtype: object
連結した列をpandas.DataFrameに追加
文字列を連結した列をpandas.DataFrame
に新規列として追加したい場合、[列名]
で新たな列名を指定して代入すればよい。
df['name_state'] = df['name'].str.cat(df['state'], sep=' in ')
print(df)
# name age state point col_NaN name_state
# 0 Alice 24 NY 64 X Alice in NY
# 1 Bob 42 CA 92 NaN Bob in CA
# 2 Charlie 18 CA 70 Z Charlie in CA
必要なくなった列はdrop()
メソッドで削除できる。
print(df.drop(columns=['name', 'state']))
# age point col_NaN name_state
# 0 24 64 X Alice in NY
# 1 42 92 NaN Bob in CA
# 2 18 70 Z Charlie in CA
assign()
を使う方法もある。assign()
を使う場合は、元のオブジェクトは変更されず新たなオブジェクトが返される。
df = pd.read_csv('data/src/sample_pandas_normal.csv').head(3)
print(df)
# name age state point
# 0 Alice 24 NY 64
# 1 Bob 42 CA 92
# 2 Charlie 18 CA 70
print(df.assign(name_state=df['name'] + ' in ' + df['state']))
# name age state point name_state
# 0 Alice 24 NY 64 Alice in NY
# 1 Bob 42 CA 92 Bob in CA
# 2 Charlie 18 CA 70 Charlie in CA
print(df.assign(name_state=df['name'] + ' in ' + df['state']).drop(columns=['name', 'state']))
# age point name_state
# 0 24 64 Alice in NY
# 1 42 92 Bob in CA
# 2 18 70 Charlie in CA