我有一个函数,它具有可选的kwargs(总共8个),基于用户输入的最小值和最大值。
例如GR_min, GR_max, GR_N_min, GR_N_max, Hi_min, Hi_max
等...其中数据帧列是GR
,GR_N
,Hi
等...
我希望数据帧过滤给定的最小值和最大值,但是如果在函数调用中没有给出一个或多个值,则将默认的最小值 - 最大值设置为列的最小值 - 最大值。
例如一些伪代码:
df = pd.DataFrame({'GR': [1, 2, 3, 4, 2, 3],
'GR_N': [0.8, 0, 1, 0.6, 0.9, 1], 'Hi':[3, 6, 2, 5, 22, 7]})
得到我:
GR GR_N Hi
0 1 0.8 3
1 2 0.0 6
2 3 1.0 2
3 4 0.6 5
4 2 0.9 22
5 3 1.0 7
我想要一个像这样的函数:
def picker(data, **kwargs):
data_filtered = data[data['GR'].between(GR_min, GR_max) &
data['GR_N'].between(GR_N_min, GR_N_max) &
data['Hi'].between(Hi_min, Hi_max)]
return data_filtered
调用后输出为:
picker(data=df, GR_min=2, GR_max=3, Hi_min=1, Hi_max=6)
GR GR_N Hi
1 2 0.0 6
2 3 1.0 2
除了显式调用数据帧的每一列,我们使用** kwargs本身来过滤。
有没有办法做到这一点?
DataFrame.query
在这里很方便,因为它将解析包含条件的字符串。因此,从关键字参数构建条件字符串就足够了。
每个单独的条件可以构建为:K<=val
用于K_max=val
参数,K>=val
用于K_min=val
参数。要构建列表,每个单独的条件必须括在括号(()
)中,然后与&
连接。
代码可以是:
def picker(data, **kwargs):
def make_cond(k,v):
if len(k)<5:
raise(ValueError('Arg too short {}'.format(k)))
if k.endswith('_min'):
return '({}>={})'.format(k[:-4], v)
elif k.endswith('_max'):
return '({}<={})'.format(k[:-4], v)
else:
raise(ValueError('Unknow arg {}'.format(k)))
strcond='&'.join((make_cond(k, v) for k,v in kwargs.items()))
# print(strcond) # uncomment for traces
return data.query(strcond)
您可以为kwargs指定默认字典,将min和max指定为-infinity和+ infinity,然后使用用户输入覆盖这些字典。像这样的东西:
import numpy as np
def picker(data, **kwargs):
d = dict(GR_min=-np.inf, GR_max=np.inf) # ... etc
kwargs = {**d, **kwargs}
data_filtered = data[data['GR'].between(kwargs["GR_min"], kwargs["GR_max"])] # ... etc
return data_filtered
我对此感到有点困惑,根据列中的最小 - 最大值进行过滤根本就不会过滤,不是吗?为什么不只是根据提供的参数进行过滤?无论如何,这听起来像默认参数的情况。
#create the DataFrame
df = pd.DataFrame({'GR': [1, 2, 3, 4, 2, 3],
'GR_N': [0.8, 0, 1, 0.6, 0.9, 1], 'Hi':[3, 6, 2, 5, 22, 7]})
def picker(df, GR_min = None, GR_max = None, GR_N_min = None, GR_N_max = None,
Hi_min = None, Hi_max = None): #use default arguments
if GR_min == None:
GR_min = df['GR'].min()
if GR_max == None:
GR_max = df['GR'].max()
if GR_N_min == None:
GR_N_min = df['GR_N'].min()
if GR_N_max == None:
GR_N_max == df['GR_N'].max()
#filter the DataFrame with masks
df_out = df.loc[(df['GR'] > GR_min) & (df['GR'] < GR_max) &
(df['GR_N'] > GR_N_min) & (df['GR_N'] < GR_N_max)]
return df_out