根据pandas
文档,应该可以使用setting with enlargment追加不存在的行DataFrame
,但在检索多个丢失的键时工作正常,设置多个缺失密钥会引发KeyError
:
import pandas as pd
print(pd.__version__) # '0.19.2'
df = pd.DataFrame([[9] * 3] * 3, index=list('ABC'))
## Show a mix of extant and missing keys:
inds_e = pd.Index(list('BCDE'))
print(df.loc[inds_e])
# 0 1 2
# B 9.0 9.0 9.0
# C 9.0 9.0 9.0
# D NaN NaN NaN
# E NaN NaN NaN
## Assign the enlarging subset to -1:
try:
df.loc[inds_e] = -1
except KeyError as e:
print(e)
# "Index(['D', 'E'], dtype='object') not in index"
设置多个现有的键可以正常工作,并且使用enlargegment设置任何一行也可以正常工作:
## Assign all the non-missing keys at once:
inds_nm = inds_e.intersection(df.index)
df.loc[inds_nm] = -1
## Assign the missing keys one at a time:
inds_m = inds_e.difference(df.index)
for ind in inds_m:
df.loc[ind] = -1
print(df)
# 0 1 2
# A 9 9 9
# B -1 -1 -1
# C -1 -1 -1
# D -1 -1 -1
# E -1 -1 -1
那就是说,这看起来非常优雅和低效。有一个very similar question here,但是使用combine_first()
功能解决了这个问题 - combine_first()
和update()
方法似乎没有与简单赋值相同的语义 - 在在combine_first
的情况下,非空值不会更新,在update
的情况下,右侧数据框中的空值不会覆盖左侧的非空值。
这是pandas
中的错误,如果没有,那么在pandas
数据框上通过放大为现有密钥和缺失密钥混合分配值的“正确”方法是什么?
修改:在pandas
github上看起来像there is an issue about this from 2014。事实上显然是使用df.reindex
,但是当我试图通过放大来分配所有键的子集时,我不清楚它是如何工作的。
答案 0 :(得分:1)
根据您的编辑,您可以在两个索引的并集上使用reindex
分配重叠和放大,然后loc
:
# Reindex to add the missing indicies (fill_value preserves integer dtype).
df = df.reindex(df.index.union(inds_e), fill_value=-1)
# Perform the assignment.
df.loc[inds_e] = -1
这似乎在这里做了一些额外的分配,因为loc
将填充fill_value
照顾的一些值。几个简单的时间似乎表明双倍填充比仅仅确定要填充的左侧位置更快。您不一定需要使用fill_value
;我只是在这种情况下用它来保存dtype。如果你有浮点而不是整数,那就完全没必要了。
结果输出:
0 1 2
A 9 9 9
B -1 -1 -1
C -1 -1 -1
D -1 -1 -1
E -1 -1 -1
<强>计时强>
这似乎相当有效。使用以下设置生成更大的示例:
n = 10**5
df = pd.DataFrame(np.random.randint(1000, size=(n, 4)))
inds = pd.Index(range(n//2, 3*n//2))
def root(df, inds):
df = df.reindex(df.index.union(inds), fill_value=-1)
df.loc[inds] = -1
return df
def paul(df, inds):
## Assign all the non-missing keys at once:
inds_nm = inds.intersection(df.index)
df.loc[inds_nm] = -1
## Assign the missing keys one at a time:
inds_m = inds.difference(df.index)
for ind in inds_m:
df.loc[ind] = -1
return df
我得到以下时间:
%timeit root(df.copy(), inds)
100 loops, best of 3: 16.5 ms per loop
我无法让您的解决方案与n=10**5
一起运行。使用n=10**4
:
%timeit paul(df.copy(), inds)
1 loop, best of 3: 14.1 s per loop