質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

Q&A

解決済

1回答

531閲覧

2つのデータフレームを左側結合(left_join)し、紐づかない行のみにdf.styleで色を塗りたい

H.K2

総合スコア88

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

0グッド

0クリップ

投稿2021/05/18 17:23

編集2021/05/18 17:25

前提・実現したいこと

以下の図のように、RDBMSなどからとってきた2つのテーブルを、あるカラムをキーにして左側結合し、紐づかない行のみを判別するために色を塗るか、判別列を追加するような処理を書きたいと思っています。

イメージ説明

データ取得してpandasのdfに取り込み、紐づかない行を抽出することはできたのですが、
これらに対し、df.styleで色を付けたりなどするとき、applyの使い方などが悪いのか、
以下のエラーが出ます。エラーについて検索したのですが、何が問題かがよくわかりませんでした。
なお、コードはVSCodeでipynbに記載し、逐次実行しています。何か良い解決方法などありましたらご教示いただけますと幸いです。
(コードが汚いかもしれませんがご容赦いただきたく…。)

発生している問題・エラーメッセージ

エラーメッセージ Int64Index([0], dtype='int64') --------------------------------------------------------------------------- TypeError Traceback (most recent call last) C:\ProgramData\Anaconda3\lib\site-packages\IPython\core\formatters.py in __call__(self, obj) 343 method = get_real_method(obj, self.print_method) 344 if method is not None: --> 345 return method() 346 return None 347 else: C:\ProgramData\Anaconda3\lib\site-packages\pandas\io\formats\style.py in _repr_html_(self) 162 Hooks into Jupyter notebook rich display system. 163 """ --> 164 return self.render() 165 166 @Appender( C:\ProgramData\Anaconda3\lib\site-packages\pandas\io\formats\style.py in render(self, **kwargs) 516 * table_attributes 517 """ --> 518 self._compute() 519 # TODO: namespace all the pandas keys 520 d = self._translate() C:\ProgramData\Anaconda3\lib\site-packages\pandas\io\formats\style.py in _compute(self) 589 r = self 590 for func, args, kwargs in self._todo: --> 591 r = func(self)(*args, **kwargs) 592 return r 593 C:\ProgramData\Anaconda3\lib\site-packages\pandas\io\formats\style.py in _apply(self, func, axis, subset, **kwargs) 597 data = self.data.loc[subset] 598 if axis is not None: --> 599 result = data.apply(func, axis=axis, result_type="expand", **kwargs) 600 result.columns = data.columns 601 else: C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\frame.py in apply(self, func, axis, broadcast, raw, reduce, result_type, args, **kwds) 6911 kwds=kwds, 6912 ) -> 6913 return op.get_result() 6914 6915 def applymap(self, func): C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\apply.py in get_result(self) 184 return self.apply_raw() 185 --> 186 return self.apply_standard() 187 188 def apply_empty_result(self): C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\apply.py in apply_standard(self) 290 291 # compute the result using the series generator --> 292 self.apply_series_generator() 293 294 # wrap results C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\apply.py in apply_series_generator(self) 319 try: 320 for i, v in enumerate(series_gen): --> 321 results[i] = self.f(v) 322 keys.append(v.name) 323 except Exception as e: <ipython-input-26-b2380a9baf71> in index_match(s) 1 def index_match(s): 2 print(result_df.index) ----> 3 is_match = s.index in result_df.index 4 return ['background-color:red' if v else '' for v in is_match] C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\indexes\numeric.py in __contains__(self, key) 209 Check if key is a float and has a decimal. If it has, return False. 210 """ --> 211 hash(key) 212 try: 213 if is_float(key) and int(key) != key: C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\indexes\base.py in __hash__(self) 4255 4256 def __hash__(self): -> 4257 raise TypeError("unhashable type: %r" % type(self).__name__) 4258 4259 def __setitem__(self, key, value): TypeError: ("unhashable type: 'RangeIndex'", 'occurred at index aa')

該当のソースコード

Python3

1ソースコード 2def index_match(s): 3 print(result_df.index) 4 is_match = s.index in result_df.index 5 return ['background-color:red' if v else '' for v in is_match] 6 7 8df_l = pd.DataFrame([["1","2",3],[4,5,6],[7,8,9]], columns=["aa","bb", "cc"]) 9df_r = pd.DataFrame([["1","2","3"],[4,5,6],[7,8,9]], columns=["dd","bb","cc"]) 10result_df = pd.merge(df_l, df_r, on=["bb", "cc"], how="left").query("dd != dd") 11 12df_l.style.apply(index_match) 13

試したこと

applyの使い方などについて検索し、試行錯誤してみた。

補足情報(FW/ツールのバージョンなど)

Python 3.7.4
pandas 0.25.1

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

index_matchの返す値は、同じ形のSeriesかDataFrameでなければならないのに、リストを返しているからです。
あてずっぽうでやらずに、docstringを読みましょう。

python

1>>> print(df.style.apply.__doc__) 2 3 Apply a function column-wise, row-wise, or table-wise. 4 5 Updates the HTML representation with the result. 6 7 Parameters 8 ---------- 9 func : function 10 ``func`` should take a Series or DataFrame (depending 11 on ``axis``), and return an object with the same shape. 12 Must return a DataFrame with identical index and 13 column labels when ``axis=None``. 14 axis : {0 or 'index', 1 or 'columns', None}, default 0 15 Apply to each column (``axis=0`` or ``'index'``), to each row 16 (``axis=1`` or ``'columns'``), or to the entire DataFrame at once 17 with ``axis=None``. 18 subset : IndexSlice 19 A valid indexer to limit ``data`` to *before* applying the 20 function. Consider using a pandas.IndexSlice. 21 **kwargs : dict 22 Pass along to ``func``. 23 24 Returns 25 ------- 26 self : Styler 27 28 Notes 29 ----- 30 The output shape of ``func`` should match the input, i.e. if 31 ``x`` is the input row, column, or table (depending on ``axis``), 32 then ``func(x).shape == x.shape`` should be true. 33 34 This is similar to ``DataFrame.apply``, except that ``axis=None`` 35 applies the function to the entire DataFrame at once, 36 rather than column-wise or row-wise. 37 38 Examples 39 -------- 40 >>> def highlight_max(x): 41 ... return ['background-color: yellow' if v == x.max() else '' 42 for v in x] 43 ... 44 >>> df = pd.DataFrame(np.random.randn(5, 2)) 45 >>> df.style.apply(highlight_max) 46

投稿2021/05/18 18:05

ppaul

総合スコア24666

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

H.K2

2021/05/20 07:41

遅くなりましてすみません。ご回答ありがとうございます! ご指摘いただきましたdoc_stringのサンプルにある、 return ['background-color: yellow' if v == x.max() else '' for v in x] と、自分の書いた個所の return ['background-color:red' if v else '' for v in is_match] は、同じ形になるのかと思っていましたが、異なるのでしょうか。 (それとも受け側が異なる、というご指摘でしょうか?)
ppaul

2021/05/20 12:30

異なります。 ['background-color: yellow' if v == x.max() else '' for v in x]はリストです。 求められているのは、同じ形のSeriesかDataFrameです。 色は付けたことがないので動くかどうかは分かりませんが、 def index_match(s): return s.reset_index()['index'].apply(lambda x: 'background-color:red' if x in result_df.index else '') を試してみてください。
H.K2

2021/05/20 23:51

ありがとうございます。試してみます!
H.K2

2021/05/21 03:42

できました!ありがとうございます。 s.reset_index()['index']の部分は、Seriesを返すために必要、ということでしょうか。 lambda文部分で、indexと一致したらスタイルに色設定をする部分を行い、それをseriesにApplyしたものをreturnしている、という考え方でよいのでしょうか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問