DataFrameから、特定の条件を満たす行を削除する方法について。
例を挙げよう。
import pandas as pd df = pd.DataFrame({ 'name' : ['Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Fred'], 'English' : [12, 34, 56, 78, -1, 90], 'Math' : [88, 66, -1, 44, 22, -1] }) df # -> name English Math 0 Alice 12 88 1 Bob 34 66 2 Charlie 56 -1 3 David 78 44 4 Eve -1 22 5 Fred 90 -1
上記の通り、生徒と試験の点数が表(DataFrame)になっているとしよう。
試験を欠席した人は点数が-1になっている、としよう。
Mathの得点を集計する前に、Mathの数値が-1である行を除外したい。
どうすればよいだろうか。
NaNを削除するのであればdropna関数が使える。しかし今回の状況では使えない。
正解
df[df['Math'] != -1] # -> name English Math 0 Alice 12 88 1 Bob 34 66 3 David 78 44 4 Eve -1 22
ちょっとした発想の転換が必要である。
「行を削除する」という発想で考えると、なかなか思いつかなかった。
-1の行を削除するので、-1でない行を選択・抽出すれば良い。
df[df.Math != -1]
でも上手くいく。'Math'の列を指定する際の書き方が違うだけだ。
別解
一応、最初に考えた方法もあわせて書いておく。
以下の方法は簡潔ではないことを注意されたい。参考と自分用の整理のために残しておく。
該当行の削除はdropでできるだろう、というところから考え始めると、こうなる。
該当する行を求めるのは以下のコードで可能である。
condition_boolen = (df["Math"] == -1) condition_boolen # -> 0 False 1 False 2 True 3 False 4 False 5 True Name: Math, dtype: bool
しかし、pandas.DataFrame.drop 関数は、True/Falseが並んでいるこの配列(Series)を引数に取れない。
df.drop(condition_boolen)
# ->
エラー(内容は下の折りたたみ部分)
エラー内容(クリックすると展開されます)
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-7-ba417e4cb86b> in <module> ----> 1 df.drop(condition_boolen) c:\program files\python37\lib\site-packages\pandas\core\frame.py in drop(self, labels, axis, index, columns, level, inplace, errors) 3695 index=index, columns=columns, 3696 level=level, inplace=inplace, -> 3697 errors=errors) 3698 3699 @rewrite_axis_style_signature('mapper', [('copy', True), c:\program files\python37\lib\site-packages\pandas\core\generic.py in drop(self, labels, axis, index, columns, level, inplace, errors) 3109 for axis, labels in axes.items(): 3110 if labels is not None: -> 3111 obj = obj._drop_axis(labels, axis, level=level, errors=errors) 3112 3113 if inplace: c:\program files\python37\lib\site-packages\pandas\core\generic.py in _drop_axis(self, labels, axis, level, errors) 3141 new_axis = axis.drop(labels, level=level, errors=errors) 3142 else: -> 3143 new_axis = axis.drop(labels, errors=errors) 3144 result = self.reindex(**{axis_name: new_axis}) 3145 c:\program files\python37\lib\site-packages\pandas\core\indexes\base.py in drop(self, labels, errors) 4402 if errors != 'ignore': 4403 raise KeyError( -> 4404 '{} not found in axis'.format(labels[mask])) 4405 indexer = indexer[~mask] 4406 return self.delete(indexer) KeyError: '[False False True False False True] not found in axis'
ではどうすれば良いかというと、 drop関数の引数には、削除したい列のindexのリストを指定する必要がある。
labels : single label or list-like Index or column labels to drop. https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.drop.html より
rows_to_drop = df.index[df["Math"] == -1] rows_to_drop # -> Int64Index([2, 5], dtype='int64') df.drop(rows_to_drop) # -> name English Math 0 Alice 12 88 1 Bob 34 66 3 David 78 44 4 Eve -1 22
"Math"が-1の行を選択する操作と、indexを取る操作とは、交換可能である。
df[df["Math"] == -1].index # -> Int64Index([2, 5], dtype='int64')
余談だが、インデックス()を df.index は df['index']と書くことはできない。エラーになる。
df['index'] # -> エラー(内容は下の折りたたみ部分)
エラー内容(クリックすると展開されます)
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) c:\program files\python37\lib\site-packages\pandas\core\indexes\base.py in get_loc(self, key, method, tolerance) 3077 try: -> 3078 return self._engine.get_loc(key) 3079 except KeyError: pandas\_libs\index.pyx in pandas._libs.index.IndexEngine.get_loc() pandas\_libs\index.pyx in pandas._libs.index.IndexEngine.get_loc() pandas\_libs\hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable.get_item() pandas\_libs\hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable.get_item() KeyError: 'index' During handling of the above exception, another exception occurred: KeyError Traceback (most recent call last) <ipython-input-11-1cd2fcbdc823> in <module> ----> 1 df['index'] c:\program files\python37\lib\site-packages\pandas\core\frame.py in __getitem__(self, key) 2686 return self._getitem_multilevel(key) 2687 else: -> 2688 return self._getitem_column(key) 2689 2690 def _getitem_column(self, key): c:\program files\python37\lib\site-packages\pandas\core\frame.py in _getitem_column(self, key) 2693 # get column 2694 if self.columns.is_unique: -> 2695 return self._get_item_cache(key) 2696 2697 # duplicate columns & possible reduce dimensionality c:\program files\python37\lib\site-packages\pandas\core\generic.py in _get_item_cache(self, item) 2487 res = cache.get(item) 2488 if res is None: -> 2489 values = self._data.get(item) 2490 res = self._box_item_values(item, values) 2491 cache[item] = res c:\program files\python37\lib\site-packages\pandas\core\internals.py in get(self, item, fastpath) 4113 4114 if not isna(item): -> 4115 loc = self.items.get_loc(item) 4116 else: 4117 indexer = np.arange(len(self.items))[isna(self.items)] c:\program files\python37\lib\site-packages\pandas\core\indexes\base.py in get_loc(self, key, method, tolerance) 3078 return self._engine.get_loc(key) 3079 except KeyError: -> 3080 return self._engine.get_loc(self._maybe_cast_indexer(key)) 3081 3082 indexer = self.get_indexer([key], method=method, tolerance=tolerance) pandas\_libs\index.pyx in pandas._libs.index.IndexEngine.get_loc() pandas\_libs\index.pyx in pandas._libs.index.IndexEngine.get_loc() pandas\_libs\hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable.get_item() pandas\_libs\hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable.get_item() KeyError: 'index'
以上。それでは。