pandasのDataFrameのセル(1つのマス)にpythonのリスト(配列)を代入しようとして、苦労したのでやり方をまとめておく。
(pandasの公式ドキュメントではセルをcellとは呼ばず、valueもしくはscalar valueと呼んでいるようだ。)
注意
おそらく、DataFrameのセルにlistを入れようとするのはあまり良い方法ではない。
この使い方を、pandas側があまり想定していないような気がする。
私がDataFrameのセルにlistを持たせたときは、色々な処理がいちいちうまく行かないので、少しやってみたけどやめてしまった。
結局データの持ち方を変えて、やりたい分析を実施した。
データの持ち方を変えて別の方法でできないか検討したほうが良いだろう。
準備
import pandas as pd import numpy as np pd.options.display.notebook_repr_html = False # jupyter notebook上での出力形式を制御するために書いています。無くても動きます。
# 動作環境の確認 print(pd.__version__) print(np.__version__) # -------------------- 1.1.2 1.19.1
df = pd.DataFrame({ 'col_A': [1.2 ,3.4, 5.6], 'col_B': [9.8, 7.6, 5.4], 'col_string': ['hello', 'good_morning', 'good_night'] }) df # -------------------- col_A col_B col_string 0 1.2 9.8 hello 1 3.4 7.6 good_morning 2 5.6 5.4 good_night
失敗例 loc, ilocだとエラーになる
上記のdfの一番右下、「good_night」と書いてあるところにリストを代入したいとしよう。
loc
やiloc
を使ってやろうとするとエラーになる。
(pandasのバージョンによっては別のエラーメッセージになるかもしれない)
my_list = ['this' , 'is', 'a', 'list']
print(df.loc[2, 'col_string']) df.loc[2, 'col_string'] = my_list # -------------------- good_night --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-5-4bd9c63f53aa> in <module> 1 print(df.loc[2, 'col_string']) ----> 2 df.loc[2, 'col_string'] = my_list /usr/local/lib/python3.8/site-packages/pandas/core/indexing.py in __setitem__(self, key, value) 668 669 iloc = self if self.name == "iloc" else self.obj.iloc --> 670 iloc._setitem_with_indexer(indexer, value) 671 672 def _validate_key(self, key, axis: int): /usr/local/lib/python3.8/site-packages/pandas/core/indexing.py in _setitem_with_indexer(self, indexer, value) 1664 if is_list_like_indexer(value) and 0 != lplane_indexer != len(value): 1665 # Exclude zero-len for e.g. boolean masking that is all-false -> 1666 raise ValueError( 1667 "cannot set using a multi-index " 1668 "selection indexer with a different " ValueError: cannot set using a multi-index selection indexer with a different length than the value
print(df.iloc[2, 2]) df.iloc[2, 2] = my_list # -------------------- good_night --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-6-dd2da9191db9> in <module> 1 print(df.iloc[2, 2]) ----> 2 df.iloc[2, 2] = my_list /usr/local/lib/python3.8/site-packages/pandas/core/indexing.py in __setitem__(self, key, value) 668 669 iloc = self if self.name == "iloc" else self.obj.iloc --> 670 iloc._setitem_with_indexer(indexer, value) 671 672 def _validate_key(self, key, axis: int): /usr/local/lib/python3.8/site-packages/pandas/core/indexing.py in _setitem_with_indexer(self, indexer, value) 1664 if is_list_like_indexer(value) and 0 != lplane_indexer != len(value): 1665 # Exclude zero-len for e.g. boolean masking that is all-false -> 1666 raise ValueError( 1667 "cannot set using a multi-index " 1668 "selection indexer with a different " ValueError: cannot set using a multi-index selection indexer with a different length than the value
DataFrameのセルにlistを代入するためには、at, iatを使う
loc
やiloc
は複数のセルを選択することもできるので、右辺が配列だと「え?これ複数のセルに代入したいんじゃないの? 左辺が単一のセルなのに右辺がセル4つ分の値なんだから、これじゃダメだよ」とpandasが勘違いするんだろう。たぶん。
pandasには必ず一つのセルを選択する(複数のセルを選択できない)関数がある。at
とiat
だ。これを使うとセルにlistを代入できる。
at
を使った例。loc
と同様に、行と列の名前で位置を指定する。
print(df.at[2, 'col_string']) df.at[2, 'col_string'] = my_list # -------------------- good_night
print(df) print('...') print(df.loc[2, 'col_string']) print(type(df.loc[2, 'col_string'])) # -------------------- col_A col_B col_string 0 1.2 9.8 hello 1 3.4 7.6 good_morning 2 5.6 5.4 [this, is, a, list] ... ['this', 'is', 'a', 'list'] <class 'list'>
iat
を使った例。iloc
と同様に、行と列の番号(何行目・何列目)で位置を指定する。
my_list = ['another', 'list'] print(df.iat[0, 2]) df.iat[0, 2] = my_list # -------------------- hello
print(df) print('...') print(df.iloc[0, 2]) print(type(df.iloc[0, 2])) # -------------------- col_A col_B col_string 0 1.2 9.8 [another, list] 1 3.4 7.6 good_morning 2 5.6 5.4 [this, is, a, list] ... ['another', 'list'] <class 'list'>
数値の列にリストを入れたい
ここまではうまく行った。しかし、数値の入っている列のセルにリストを代入しようとするとエラーが生じる。
my_list = [3, 4, 5] print(df.at[0, 'col_A']) df.at[0, 'col_A'] = my_list # -------------------- 1.2 --------------------------------------------------------------------------- TypeError Traceback (most recent call last) TypeError: float() argument must be a string or a number, not 'list' The above exception was the direct cause of the following exception: ValueError Traceback (most recent call last) <ipython-input-12-02f17b50862e> in <module> 1 my_list = [3, 4, 5] 2 print(df.at[0, 'col_A']) ----> 3 df.at[0, 'col_A'] = my_list /usr/local/lib/python3.8/site-packages/pandas/core/indexing.py in __setitem__(self, key, value) 2089 return 2090 -> 2091 return super().__setitem__(key, value) 2092 2093 /usr/local/lib/python3.8/site-packages/pandas/core/indexing.py in __setitem__(self, key, value) 2040 raise ValueError("Not enough indexers for scalar access (setting)!") 2041 -> 2042 self.obj._set_value(*key, value=value, takeable=self._takeable) 2043 2044 /usr/local/lib/python3.8/site-packages/pandas/core/frame.py in _set_value(self, index, col, value, takeable) 3145 validate_numeric_casting(series.dtype, value) 3146 -> 3147 series._values[loc] = value 3148 # Note: trying to use series._set_value breaks tests in 3149 # tests.frame.indexing.test_indexing and tests.indexing.test_partial ValueError: setting an array element with a sequence.
これはデータ型(dtype)の問題である。
col_A
の列は浮動小数点数を1つ入れるデータ型になっているので、配列を代入しようとするとデータ型が合わずにエラーになるのだ。
pandasのdtypeについては、こちらも参照。公式ドキュメントを個人的に翻訳した記事だ。
df.dtypes # -------------------- col_A float64 col_B float64 col_string object dtype: object
listを入れるならば、該当する列のデータ型をobjectにすれば良い。それにはastype()関数を用いる。
df['col_A'] = df['col_A'].astype('object') df.dtypes # -------------------- col_A object col_B float64 col_string object dtype: object
print(df.at[0, 'col_A']) df.at[0, 'col_A'] = my_list # -------------------- 1.2
df # -------------------- col_A col_B col_string 0 [3, 4, 5] 9.8 [another, list] 1 3.4 7.6 good_morning 2 5.6 5.4 [this, is, a, list]
参考文献
Python pandas insert list into a cell - Stack Overflow
python - pandas: how to store a list in a dataframe? - Stack Overflow
それでは。