Pandas中用query赋值np.nan失效?原因及解决方法
解决Pandas中用
query修改DataFrame失效的问题 首先,咱们明确你的核心需求:当Target10列为空值时,把Price列对应行设为np.nan。你已经用where方法实现了需求,但尝试query时发现没修改原DataFrame,这其实是Pandas中常见的副本/视图差异导致的。
为什么你的query方法失效?
当你执行toy_data.query('Target10.isnull()', engine='python').Price = np.nan时,问题出在链式索引的特性上:
toy_data.query(...)返回的是原DataFrame的临时副本,不是对原数据的直接引用。- 后续对
.Price赋值,只是修改了这个临时副本,原DataFrame根本没被触动。 - 有时候Pandas不会抛出
SettingWithCopyWarning,但这不代表操作有效,原数据还是原样。
正确用query实现目标的两种方式
方式1:通过索引定位修改(推荐,高效)
先通过query拿到符合条件的行的索引,再用loc直接修改原DataFrame的对应列——这是最直接且高效的方法:
import pandas as pd import numpy as np # 构造示例数据 data = {"Price":{"1581292800000":21.6800003052,"1581379200000":21.6000003815,"1581465600000":21.6000003815,"1581552000000":21.6000003815,"1581638400000":22.1599998474,"1581984000000":21.9300003052,"1582070400000":22.0,"1582156800000":21.9300003052,"1582243200000":22.0200004578,"1582502400000":21.8899993896,"1582588800000":21.9699993134,"1582675200000":21.9599990845,"1582761600000":21.8500003815,"1582848000000":22.0300006866,"1583107200000":21.8600006104,"1583193600000":21.8199996948,"1583280000000":21.9699993134,"1583366400000":22.0100002289,"1583452800000":21.7399997711,"1583712000000":21.5100002289},"Target10":{"1581292800000":22.9500007629,"1581379200000":23.1000003815,"1581465600000":23.0300006866,"1581552000000":22.7999992371,"1581638400000":22.9599990845,"1581984000000":22.5799999237,"1582070400000":22.3799991608,"1582156800000":22.25,"1582243200000":22.4699993134,"1582502400000":22.2900009155,"1582588800000":22.3248996735,"1582675200000":None,"1582761600000":None,"1582848000000":None,"1583107200000":None,"1583193600000":None,"1583280000000":None,"1583366400000":None,"1583452800000":None,"1583712000000":None}} toy_data = pd.DataFrame(data) # 步骤1:获取Target10为空的行的索引 null_indices = toy_data.query('Target10.isnull()', engine='python').index # 步骤2:直接修改原DataFrame的Price列 toy_data.loc[null_indices, 'Price'] = np.nan
方式2:拆分合并(不推荐,适合小数据集)
如果想全程用query操作,可以把数据拆分为有效行和空值行,修改空值行的Price后再合并:
# 筛选Target10非空的行,保留原Price valid_rows = toy_data.query('Target10.notnull()', engine='python') # 筛选Target10为空的行,将Price设为np.nan null_rows = toy_data.query('Target10.isnull()', engine='python').assign(Price=np.nan) # 合并并替换原DataFrame toy_data = pd.concat([valid_rows, null_rows])
这种方式会创建多个临时DataFrame,大数据集下效率不如方式1。
补充:优化你的where方法
你之前的where代码可以更清晰一点,直接指定替换值为np.nan,然后赋值回原列:
toy_data['Price'] = toy_data.Price.where(toy_data.Target10.notnull(), np.nan)
这样逻辑更明确,别人读代码时一眼就能懂替换的是空值。
内容的提问来源于stack exchange,提问作者user8270077
相关产品推荐
相关产品推荐

