[英]Pandas - replace all NaN values in DataFrame with empty python dict objects
我有一个pandas DataFrame,其中每个单元格都包含一个python dict。
>>> data = {'Q':{'X':{2:2010}, 'Y':{2:2011, 3:2009}},'R':{'X':{1:2013}}}
>>> frame = DataFrame(data)
>>> frame
Q R
X {2: 2010} {1: 2013}
Y {2: 2011, 3: 2009} NaN
我想用一个空的 dict 替换 NaN,以获得这个结果:
Q R
X {2: 2010} {1: 2013}
Y {2: 2011, 3: 2009} {}
但是,因为fillna
函数不是将空字典解释为标量值,而是作为列 --> 值的映射,所以如果我只是这样做(即它不起作用),它什么也不做:
>>> frame.fillna(inplace=True, value={})
Q R
X {2: 2010} {1: 2013}
Y {2: 2011, 3: 2009} NaN
有什么办法可以使用fillna
来完成我想要的吗? 我是否必须遍历整个 DataFrame 或构建一个愚蠢的字典,并将所有列映射到空字典?
我能够以这种方式使用DataFrame.applymap
:
>>> from pandas import isnull
>>> frame=frame.applymap(lambda x: {} if isnull(x) else x)
>>> frame
Q R
X {2: 2010} {1: 2013}
Y {2: 2011, 3: 2009} {}
此解决方案避免了 EdChum 解决方案(其中所有 NaN 单元最终指向内存中相同的底层 dict 对象,防止它们彼此独立更新)和 Shashank 解决方案(其中一个潜在的大型数据结构需要使用嵌套结构)中的陷阱dicts,只是为了指定一个空的 dict 值)。
DataFrame.where
是一种非常直接地实现这一目标的方法:
>>> data = {'Q': {'X': {2: 2010}, 'Y': {2: 2011, 3: 2009}}, 'R': {'X': {1: 2013}}}
>>> frame = DataFrame(data)
>>> frame
Q R
X {2: 2010} {1: 2013}
Y {2: 2011, 3: 2009} NaN
>>> frame.where(frame.notna(), lambda x: [{}])
Q R
X {2: 2010} {1: 2013}
Y {2: 2011, 3: 2009} {}
此外,它似乎有点快:
>>> %timeit frame.where(frame.notna(), lambda x: [{}])
791 µs ± 16.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> %timeit frame.applymap(lambda x: {} if isnull(x) else x)
1.07 ms ± 7.15 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
(在较大的数据集上,我观察到了 ~10 倍的加速)
问题在于,当 dict 传递给fillna
,它会尝试根据框架中的列填充值。 所以我尝试的第一个解决方案是 -
frame.fillna({column: {} for column in frame.columns})
但是,如果像这样在第二级提供字典,它会尝试将键与索引进行匹配,因此有效的解决方案是 -
frame.fillna({column: {ind: {} for ind in frame.index} for column in frame.columns})
这使 -
Q R
X {2: 2010} {1: 2013}
Y {2: 2011, 3: 2009} {}
EdChum 的答案可能更适合您的需求,但是当您不想进行适当的更改时可以使用它。
编辑:上述解决方案适用于较小的框架,但对于较大的框架可能是一个问题。 使用replace
可以解决这个问题。
frame.replace(np.nan, {column: {} for column in frame.columns})
这适用于loc
:
In [6]:
frame.loc[frame['R'].isnull(), 'R'] = {}
frame
Out[6]:
Q R
X {2: 2010} {1: 2013}
Y {2: 2011, 3: 2009} {}
使用.values
访问器直接分配给 numpy 数组:
frame.R = frame.R.astype(object) # assertion
frame.R.values[frame.R.isnull()] = {}
@Josh_Bode 的回答对我帮助很大。 这是一个略有不同的版本。 我使用了 mask() 而不是 where() (非常微不足道的变化)。 我还更新了分配空字典的方式。 通过创建一个与框架一样长的 dict 实例列表然后分配它,我避免了同一 dict 的许多副本的陷阱。
>>> data = {'Q': {'X': {2: 2010}, 'Y': {2: 2011, 3: 2009}}, 'R': {'X': {1: 2013}}}
>>> frame = DataFrame(data)
>>> frame
Q R
X {2: 2010} {1: 2013}
Y {2: 2011, 3: 2009} NaN
>>> frame.mask(frame.isna(), lambda x: [{} for _ in range(len(frame)])
Q R
X {2: 2010} {1: 2013}
Y {2: 2011, 3: 2009} {}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.