Python 如何使用布尔掩码对数据帧的分层列进行赋值?
我有这样一个数据帧:Python 如何使用布尔掩码对数据帧的分层列进行赋值?,python,pandas,boolean-expression,hierarchical,Python,Pandas,Boolean Expression,Hierarchical,我有这样一个数据帧: import pandas as pd df = pd.DataFrame({ "time": [1, 2, 1, 2], "site": ['a', 'a', 'b', 'b'], "val1": [11, 12, 21, 22], "val2": [101, 102, 201, 202] }) df.set_index(['time', 'site'], inplace=True, append=False) df = df.unst
import pandas as pd
df = pd.DataFrame({
"time": [1, 2, 1, 2],
"site": ['a', 'a', 'b', 'b'],
"val1": [11, 12, 21, 22],
"val2": [101, 102, 201, 202]
})
df.set_index(['time', 'site'], inplace=True, append=False)
df = df.unstack("site")
print df
val1 val2
site a b a b
time
1 11 21 101 201
2 12 22 102 202
ix = (df.val1 > 20) | (df.val2 < 102)
df.val1[ix] = 50
df.val2[ix] = 150
我想更改一些与布尔过滤器匹配的值。e、 g:
ix = df.val1 > 20
print ix
site a b
time
1 False True
2 False True
尝试的自然方法是df.val1[ix]=50
。这会执行预期的赋值,但会给出一个警告:SettingWithCopyWarning:试图在数据帧的切片副本上设置值。尝试改用.loc[row\u indexer,col\u indexer]=value
因此,现在我正在尝试使用df.loc
实现类似的功能。但是我找不到任何方法将df.loc
与这种布尔掩码一起使用。这似乎是因为我使用的是分层列,也就是说,如果我只有一组值(val1),我不会有太多问题。不幸的是,在层次结构列上使用布尔过滤器的赋值在本文中没有很好地介绍
我试图引用df.loc[:,'val1',ix]
,但这会导致索引错误:索引器太多。我已经尝试了df.loc[:,'val1'][ix]=50
,这是可行的,但给出了带有copywarning的设置
我可以使用df.val1=df.val1.where(~ix,other=50)
,但这似乎不直观、低效且不灵活(例如,无法轻松扩展以在现有值上添加10)
是否有其他基于布尔掩码的索引方法可用于为数据帧的层次列赋值
编辑以扩展问题:
我没有意识到这会是一个问题,但我实际上希望根据val1
和val2
列中的值进行过滤,并更改这两组列中的值,如下所示:
import pandas as pd
df = pd.DataFrame({
"time": [1, 2, 1, 2],
"site": ['a', 'a', 'b', 'b'],
"val1": [11, 12, 21, 22],
"val2": [101, 102, 201, 202]
})
df.set_index(['time', 'site'], inplace=True, append=False)
df = df.unstack("site")
print df
val1 val2
site a b a b
time
1 11 21 101 201
2 12 22 102 202
ix = (df.val1 > 20) | (df.val2 < 102)
df.val1[ix] = 50
df.val2[ix] = 150
ix=(df.val1>20)|(df.val2<102)
df.val1[ix]=50
df.val2[ix]=150
有没有一种简单的索引方法可以做到这一点?使用numpy ndarray非常简单,但使用pandas数据帧似乎要复杂得多。您可以使用列表来选择列
idx = df[['val1']] > 20
idx
Out[39]:
val1
site a b
time
1 False True
2 False True
df[idx] = 50
df
Out[41]:
val1 val2
site a b a b
time
1 11 50 101 201
2 12 50 102 202
当您首先按列名从数据帧中选择序列,然后尝试使用布尔掩码并为其赋值时,就会出现此问题。具体来说,带有布尔掩码的赋值在内部转换为提取的_数据。其中(-mask,other=value,inplace=True),这将引发设置WithCopyWarning
如果pandas能够保证这种操作会改变原始数据帧,而不是发出警告,那就太好了。(顺便说一下,如果链式操作的顺序颠倒,df[ix][“val1”]=500
或df[ix][[“val1”,“val2”]=500
不会发出警告,但无法更新原始数据帧)。在解决这一问题之前,有两个变通办法
(1) 受@cncggvg答案的启发:构造一个指定所有需要更新的元素的索引,而不是将两个索引操作链接在一起
# create a partial index for the boolean operation
# note: this specifies the second-level columns it will act on, but not
# the first level, since that was given unambiguously in the df[col] expression
ix = (df["val1"] > 20) | (df["val2"] < 102)
# build an index that specifies both the first and second-level columns
ix2 = pd.concat({"val1": ix}, axis=1)
# or, to do the same assignment on multiple first-level columns:
ix2 = pd.concat({"val1": ix, "val2": ix}, axis=1)
# do the assignment in one step, with no chaining
df[ix2] = 50
# or derive new values from current values
df[ix2] = df[ix2]+50
这两者都比我想要的更麻烦,所以我可以将数据帧的相关部分复制到numpy阵列中,然后从那里开始处理它们。根据的说法,这应该会有更好的性能。您是否可以选择将列展平?谢谢,这是对我所问问题的一个很好的回答。不幸的是,我忘了提到我还想更改val2列中的相应条目,类似于ix=(df.val1>20)|(df.val2>200);df.val1[ix]=50;df.val2[ix]=150
。你知道怎么做吗?用标准的numpy Ndaray很简单,但在熊猫身上似乎更棘手。