我有一个缺少值的数据框。
import pandas as pd
import numpy as np
np.random.seed([3,1415])
df = pd.DataFrame(np.random.choice((0, np.nan), (5, 5)))
print df
0 1 2 3 4
0 0.0 NaN 0.0 NaN 0.0
1 0.0 NaN 0.0 NaN NaN
2 NaN NaN 0.0 NaN NaN
3 0.0 NaN 0.0 0.0 0.0
4 0.0 0.0 0.0 0.0 0.0
如何在传递缺少单元格的行和列索引值时,使用函数返回的内容有效地填充缺失值。
假设我的函数f
定义为:
f = lambda i, j: i ** 2 - np.sqrt(abs(j))
我希望得到:
0 1 2 3 4
0 0.0 -1.0 0.0 -1.732051 0.0
1 0.0 0.0 0.0 -0.732051 -1.0
2 4.0 3.0 0.0 2.267949 2.0
3 0.0 8.0 0.0 0.000000 0.0
4 0.0 0.0 0.0 0.000000 0.0
到目前为止,我已经创建了两个函数来生成此输出:
def pir1(df, f):
dfi = df.stack(dropna=False).index.to_series().unstack()
return df.combine_first(dfi.applymap(lambda x: f(*x)))
def pir2(df, f):
dfc = df.copy()
for i in dfc.index:
for j in dfc.columns:
dfv = df.get_value(i, j)
dfc.at[i, j] = dfv if pd.notnull(dfv) else f(i, j)
return dfc
%%timeit
pir1(df, f)
100 loops, best of 3: 3.74 ms per loop
%%timeit
pir2(df, f)
1000 loops, best of 3: 714 µs per loop
任何人都可以改进吗?
答案 0 :(得分:2)
arraymap
中的pir1
和pir2
中的双重for循环调用f
一次
每对索引和列值。如果f
可以被矢量化 - 即定义
以便接受NumPy数组作为输入而不是标量,然后是大输入
通过将整个2D数组传递给f
,可以大大加快计算速度。
对于您发布的f
,无需进行任何更改; f
已经过矢量化 - 它可以
接受数组作为输入就像标量一样容易。
import numpy as np
import pandas as pd
np.random.seed([3,1415])
df = pd.DataFrame(np.random.choice((0, np.nan), (5, 5)))
def f(i, j): return i ** 2 - np.sqrt(abs(j))
def using_meshgrid(df, f):
I, J = np.meshgrid(df.index, df.columns, sparse=True, indexing='ij')
return df.combine_first(pd.DataFrame(f(I, J), index=df.index, columns=df.columns))
def pir1(df, f):
dfi = df.stack(dropna=False).index.to_series().unstack()
return df.combine_first(dfi.applymap(lambda x: f(*x)))
def pir2(df, f):
dfc = df.copy()
for i in dfc.index:
for j in dfc.columns:
dfv = df.get_value(i, j)
dfc.at[i, j] = dfv if pd.notnull(dfv) else f(i, j)
return dfc
对于小输入,pir2
仍然是最快的:
In [290]: %timeit using_meshgrid(df, f)
100 loops, best of 3: 2.01 ms per loop
In [291]: %timeit pir1(df, f)
100 loops, best of 3: 4.61 ms per loop
In [292]: %timeit pir2(df, f)
1000 loops, best of 3: 825 µs per loop
但是对于大输入,using_meshgrid
更快:
In [293]: df = pd.DataFrame(np.random.choice((0, np.nan), (500, 500)))
In [294]: %timeit using_meshgrid(df, f)
10 loops, best of 3: 160 ms per loop
In [295]: %timeit pir1(df, f)
1 loop, best of 3: 1.15 s per loop
In [296]: %timeit pir2(df, f)
1 loop, best of 3: 4.79 s per loop
答案 1 :(得分:2)
本文中列出了一种方法np.nonzero
来获取这些索引并计算这些索引的函数输出。此外,我们将使用df.values
将基础数据作为数组作为视图提取出来,从而为我们带来两个好处 -
可以使用NumPy funcs / operations来获得良好的性能。
只需将值分配到提取的数组中,就可以根据需要为此问题设置输出值,这是输入数据帧的视图。
因此,我们会有一个实现,如此 -
def using_nonzeros(df, f):
a = df.values
r,c = np.nonzero(np.isnan(a))
a[r,c] = f(r,c)
并且函数f
是可自定义的,并且对于如此定义的所述问题 -
def f(i, j): return i ** 2 - np.sqrt(abs(j))
运行时测试 -
In [223]: df = pd.DataFrame(np.random.choice((0, np.nan), (1000, 1000)))
In [224]: %timeit using_meshgrid(df,f) # @unutbu's soln
1 loops, best of 3: 823 ms per loop
In [225]: %timeit using_nonzeros(df,f) # This changes df
100 loops, best of 3: 4.61 ms per loop