为了扩展接受的答案,应用调用可能会特别昂贵 - 没有它也可以通过从头构造一个 numpy 数组来完成相同的任务。
isna = df['x'].isna()
df.loc[isna, 'x'] = pd.Series([[]] * isna.sum()).values
快速时间比较:
def empty_assign_1(s):
s[s.isna()].apply(lambda x: [])
def empty_assign_2(s):
[[]] * s.isna().sum()
series = pd.Series(np.random.choice([1, 2, np.nan], 1000000))
%timeit empty_assign_1(series)
>>> 61 ms ± 964 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit empty_assign_2(series)
>>> 2.17 ms ± 70.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
快近 10 倍!
编辑:
修复了@valentin 指出的错误
在这种情况下执行赋值时,您必须小心处理数据类型。在上面的示例中,测试系列是浮动的,但是,添加 [] 元素会强制整个系列成为对象。如果您执行类似的操作,Pandas 会为您处理这些事情
idx = series.isna()
series[isna] = series[isna].apply(lambda x: [])
因为 apply 的输出本身就是一个系列。您可以像这样使用分配开销测试实时性能(我添加了一个字符串值,因此系列是一个对象,您可以改为使用数字作为替换值而不是空列表以避免强制)。
def empty_assign_1(s):
idx = s.isna()
s[idx] = s[idx].apply(lambda x: [])
def empty_assign_2(s):
idx = s.isna()
s.loc[idx] = [[]] * idx.sum()
series = pd.Series(np.random.choice([1, 2, np.nan, '2'], 1000000))
%timeit empty_assign_1(series.copy())
>>> 45.1 ms ± 386 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit empty_assign_2(series.copy())
>>> 24 ms ± 393 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
其中大约 4 毫秒与副本有关,10 倍到 2 倍,仍然相当不错。