列がMultiIndexで列名が重複されているDataFrameに対して、`df[df["col"]>0]`のように絞り込もうとすると期待通りの結果にならない

# 環境
* Python 3.11.2
* pandas 2.0.2


# やりたいこと
MultiIndexである列を持つDataFrameに対して、行を絞り込みたいです。
以下のようなコードで実現したいです。

```
In [372]: data = [[numpy.nan, 2, 3], [4, numpy.nan, 6], [7, 8, numpy.nan]]

In [376]: df = pandas.DataFrame(data, columns=pandas.MultiIndex.from_tuples([("x","a"),("y","b"),("z","c")]))

In [377]: df
Out[377]: 
     x    y    z
     a    b    c
0  NaN  2.0  3.0
1  4.0  NaN  6.0
2  7.0  8.0  NaN

In [378]: df[df[("y","b")]>0]
Out[378]: 
     x    y    z
     a    b    c
0  NaN  2.0  3.0
2  7.0  8.0  NaN
```

# 起きたこと

列名が重複していて、かつ列名がソートされている状態のDataFrameがあります。
このDataFrameに対して、同様のコードで行を絞り込もうとすると期待する結果になりませんでした。
絞り込まれたDataFrameでは`("y","b")`列の値は正しいのです。しかし、`("x","a")`列はすべてNaNになっていました。

```
In [391]: df1 = pandas.DataFrame(data, columns=pandas.MultiIndex.from_tuples([("x","a"),("x","a"),("y","b")]))

In [392]: df1
Out[392]: 
     x         y
     a    a    b
0  NaN  2.0  3.0
1  4.0  NaN  6.0
2  7.0  8.0  NaN

# ("x","a")列がすべてNaNになっている
In [394]: df1[df1[("y","b")]>0]
Out[394]: 
    x        y
    a   a    b
0 NaN NaN  3.0
1 NaN NaN  6.0
2 NaN NaN  NaN
```

# 原因と解決策
1つずつ確認していきます。

```
In [395]: df1[("y","b")]
Out[395]: 
     y
     b
0  3.0
1  6.0
2  NaN

In [396]: type(df1[("y","b")])
Out[396]: pandas.core.frame.DataFrame

In [397]: df1[("y","b")]>0
Out[397]: 
       y
       b
0   True
1   True
2  False
```

`df1[("y","b")]`は`pandas.Series`ではなく`DataFrame`でした。
そのため、`df1[df1[("y","b")]>0]`で行を絞り込むと、`("y","b")`列以外が`NaN`になるようです。

`iloc[:,0]`で0番目の列を取得して`Series`を取得すれば、期待通り絞り込むことができました。


```
In [398]: df1[("y","b")].iloc[:,0]>0
Out[398]: 
0     True
1     True
2    False
Name: (y, b), dtype: bool

In [399]: df1[df1[("y","b")].iloc[:,0]>0]
Out[399]: 
     x         y
     a    a    b
0  NaN  2.0  3.0
1  4.0  NaN  6.0
```

# 他に検証したこと
## 列名が重複していて、かつ列名がソートされていない場合
列名が重複していて、かつ列名がソートされていない状態のDataFrameで絞り込もうとすると、`ValueError`が発生しました。


```

In [400]: df2 = pandas.DataFrame(data, columns=pandas.MultiIndex.from_tuples([("x","a"),("y","b"),("x","a")]))
     ...: 
     ...: 

In [401]: df2
Out[401]: 
     x    y    x
     a    b    a
0  NaN  2.0  3.0
1  4.0  NaN  6.0
2  7.0  8.0  NaN

In [402]: df2[df2[("y","b")]>0]
<ipython-input-402-784a8fa103c9>:1: PerformanceWarning: indexing past lexsort depth may impact performance.
  df2[df2[("y","b")]>0]
---------------------------------------------------------------------------
ValueError: cannot handle a non-unique multi-index!
```


原因は先ほどと同じなので、`iloc[:,0]`で`pandas.Series`を取得すれば、絞り込むことができました。

```
In [404]: df2[df2[("y","b")].iloc[:,0]>0]
<ipython-input-404-e6c5b3f34f81>:1: PerformanceWarning: indexing past lexsort depth may impact performance.
  df2[df2[("y","b")].iloc[:,0]>0]
Out[404]: 
     x    y    x
     a    b    a
0  NaN  2.0  3.0
2  7.0  8.0  NaN

```

ただし、列名がソートされていないと`PerformanceWarning`が発生しました。


## 列が`Index`の場合
列が`MultiIndex`ではなく`Index`の場合は、重複していない列でアクセスすると`Series`を取得できます。したがって、期待通り絞り込むことができました。


```
In [408]: df3 = pandas.DataFrame(data, columns=["x","x","y"])

In [419]: df3
Out[419]: 
     x    x    y
0  NaN  2.0  3.0
1  4.0  NaN  6.0
2  7.0  8.0  NaN

In [409]: df3["y"]
Out[409]: 
0    3.0
1    6.0
2    NaN
Name: y, dtype: float64

In [410]: df3[df3["y"]>0]
Out[410]: 
     x    x    y
0  NaN  2.0  3.0
1  4.0  NaN  6.0
```


# まとめ
以下のブログのケースもそうなのですが、`MultiIndex`で重複している場合は予期しない動作になることが多そうです。`MultiIndex`は常に一意にしておくのがよさそうです。


https://qiita.com/yuji38kwmt/items/18af4a399410afc4cf37