python - 使用另一个多索引系列屏蔽数据框

标签 python python-3.x pandas dataframe multi-index

我有一个 Dataframe,我想用多索引系列的 bool 值屏蔽(转换为 NaN),其中系列的多索引也是 Dataframe 中的列名。例如,如果 df 是:

df = pd.DataFrame({ 'A': (188, 750, 1330, 1385, 188, 750, 810, 1330, 1385),
                     'B': (1, 2, 4, 5, 1, 2, 3, 4, 5),
                     'C': (2, 5, 7, 2, 5, 5, 3, 7, 2),
                     'D': ('foo', 'foo', 'foo', 'foo', 'bar', 'bar', 'bar', 'bar', 'bar') })

    A    B  C   D
0   188  1  2   foo
1   750  2  5   foo
2   1330 4  7   foo
3   1385 5  2   foo
4   188  1  5   bar
5   750  2  5   bar
6   810  3  3   bar
7   1330 4  7   bar
8   1385 5  2   bar

多索引系列 ser 是:

arrays = [('188', '750', '810', '1330', '1385'),
          ('1', '2', '3', '4', '5')]
tuples = list(zip(*arrays))
index = pd.MultiIndex.from_tuples(tuples, names=['A', 'B'])
ser = pd.Series([False, False, True, False, True], index=index)

A     B
188   1    False
750   2    False
810   3    True
1330  4    False
1385  5    True
dtype: bool

我如何屏蔽(转换为 NaN)df 中列 C 的值,其中条目在系列 中为 False >ser,以便以最终的 Dataframe 结束,如下所示:

    A    B  C   D
0   188  1  2   foo
1   750  2  5   foo
2   1330 4  7   foo
3   1385 5  NaN foo
4   188  1  5   bar
5   750  2  5   bar
6   810  3  NaN bar
7   1330 4  7   bar
8   1385 5  NaN bar

最佳答案

更改ser的初始化步骤:

arrays = [('188', '750', '810', '1330', '1385'),
          ('1', '2', '3', '4', '5')]
# Note: The change is in this step - make the levels numeric.
tuples = list(zip(*map(pd.to_numeric, arrays)))
index = pd.MultiIndex.from_tuples(tuples, names=['A', 'B'])
ser = pd.Series([False, False, True, False, True], index=index)

初始化 index 的级别,使其具有与“A”和“B”相同的 dtype。希望这不应该成为问题。

这将使我们能够使用 loc 和基于索引的选择和分配来构建一个更简单的解决方案。

u = df.set_index(['A', 'B'])
u.loc[ser.index[ser], 'C'] = np.nan

u.reset_index()
      A  B    C    D
0   188  1  2.0  foo
1   750  2  5.0  foo
2  1330  4  7.0  foo
3  1385  5  NaN  foo
4   188  1  5.0  bar
5   750  2  5.0  bar
6   810  3  NaN  bar
7  1330  4  7.0  bar
8  1385  5  NaN  bar

如果您遇到给定 ser 并且需要更改索引的 dtype 的情况,您可以使用 pd 中的列表理解快速重新构建它。 Index.set_levels.

ser.index = ser.index.set_levels([l.astype(int) for l in ser.index.levels]) 
# Alternative,
# ser.index = ser.index.set_levels([
#     pd.to_numeric(l) for l in ser.index.levels]) 

现在,这有效:

u = df.set_index(['A', 'B'])
u.loc[ser.index[ser], 'C'] = np.nan

u.reset_index()

      A  B    C    D
0   188  1  2.0  foo
1   750  2  5.0  foo
2  1330  4  7.0  foo
3  1385  5  NaN  foo
4   188  1  5.0  bar
5   750  2  5.0  bar
6   810  3  NaN  bar
7  1330  4  7.0  bar
8  1385  5  NaN  bar

注意 loc 中的 ser.index[ser] 索引步骤,我们使用 ser 的索引而不是 index直接。

关于python - 使用另一个多索引系列屏蔽数据框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53832113/

相关文章:

python - 类型错误 : object supporting the buffer API required in flask api

python - 如何使用不同的标记分隔符连接多个 Pandas DataFrame 列?

python - 在 bool 列上过滤时 pandas 中的 FutureWarning

python - 我必须为 argparse.FileType 指定什么模式来追加,保持 - 作为默认值

python - 使用 amsmath 和 sfmath 进行绘图标记的 Latex 字体样式问题

r - 如何检测条件连续发生 3 次且具有优先级的情况?

Python 3 : subprocess. run ('mv' )使目标保持打开状态

python-3.x - 如何从 .h5 文件正确加载带有自定义层的 Keras 模型?

python - 当某些列有多个分隔符时,将 pandas 数据框从宽转换为长

python spacy 在窗口中寻找两个(或更多)单词