有没有办法从数据框中填充 np select 条件?
Is there a way to populate np select conditions from a dataframe?
考虑这样的查找 table:
lower_bound upper_bound category
0 3 6 A
1 10 40 B
2 80 200 C
3 350 600 D
4 900 1500 E
然后,有一个DataFrame我们需要根据以上条件进行分类的元素:
id value
0 id_1 20
1 id_2 500
2 id_3 1000
这些项目中的每一个都将根据它们的值进行分类,这些值应该在查找 table 中存在的指定范围之一之间。所以:
id value category
0 id_1 20 B
1 id_2 500 D
2 id_3 1000 E
我试过以下方法,有效:
conditions = []
choices = []
for condition in lookup_df.to_dict('records'):
conditions.append(
(df['value'].between(condition['lower_bound'], condition['upper_bound']))
)
choices.append(condition['category'])
之后:
df['category'] = np.select(conditions, choices, default=np.nan)
有没有办法在不转换为 dict 和循环查找 DataFrame 的情况下生成条件?
您可以使用 numpy 广播。这个想法是创建一个布尔掩码,对于每个“值”落入 lookup_df
的范围,returns 为真。然后 select 使用布尔索引的匹配值。
vals = df['value'].to_numpy()
msk = (lookup_df[['lower_bound']].to_numpy() < vals) & (vals < lookup_df[['upper_bound']].to_numpy())
df['category'] = lookup_df[['category']].to_numpy().repeat(len(df), axis=1)[msk]
输出:
id value category
0 id_1 20 B
1 id_2 500 D
2 id_3 1000 E
如果您想要任何范围之外的值的 NaN 值,dot
乘积在这里效果最好(这与 完全相同):
vals = df[['value']].to_numpy()
msk = (lookup_df['lower_bound'].to_numpy() < vals) & (vals < lookup_df['upper_bound'].to_numpy())
df = df.assign(category=msk.dot(lookup_df['category'])).replace('', float('nan'))
你可以使用 pd.merge_asof
:
output = pd.merge_asof(df, lookup_df[["lower_bound","category"]], left_on="value", right_on="lower_bound").drop("lower_bound", axis=1)
>>> output
id value category
0 id_1 20 B
1 id_2 500 D
2 id_3 1000 E
您可以使用 np.dot
:
vals = np.vstack(df['value'].values)
lb = condition['lower_bound'].values <= vals
ub = vals <= condition['upper_bound'].values
df['category'] = np.dot(lb & ub, condition['category'])
输出:
id
value
category
id_1
20
B
id_2
500
D
id_3
1000
E
考虑这样的查找 table:
lower_bound upper_bound category
0 3 6 A
1 10 40 B
2 80 200 C
3 350 600 D
4 900 1500 E
然后,有一个DataFrame我们需要根据以上条件进行分类的元素:
id value
0 id_1 20
1 id_2 500
2 id_3 1000
这些项目中的每一个都将根据它们的值进行分类,这些值应该在查找 table 中存在的指定范围之一之间。所以:
id value category
0 id_1 20 B
1 id_2 500 D
2 id_3 1000 E
我试过以下方法,有效:
conditions = []
choices = []
for condition in lookup_df.to_dict('records'):
conditions.append(
(df['value'].between(condition['lower_bound'], condition['upper_bound']))
)
choices.append(condition['category'])
之后:
df['category'] = np.select(conditions, choices, default=np.nan)
有没有办法在不转换为 dict 和循环查找 DataFrame 的情况下生成条件?
您可以使用 numpy 广播。这个想法是创建一个布尔掩码,对于每个“值”落入 lookup_df
的范围,returns 为真。然后 select 使用布尔索引的匹配值。
vals = df['value'].to_numpy()
msk = (lookup_df[['lower_bound']].to_numpy() < vals) & (vals < lookup_df[['upper_bound']].to_numpy())
df['category'] = lookup_df[['category']].to_numpy().repeat(len(df), axis=1)[msk]
输出:
id value category
0 id_1 20 B
1 id_2 500 D
2 id_3 1000 E
如果您想要任何范围之外的值的 NaN 值,dot
乘积在这里效果最好(这与
vals = df[['value']].to_numpy()
msk = (lookup_df['lower_bound'].to_numpy() < vals) & (vals < lookup_df['upper_bound'].to_numpy())
df = df.assign(category=msk.dot(lookup_df['category'])).replace('', float('nan'))
你可以使用 pd.merge_asof
:
output = pd.merge_asof(df, lookup_df[["lower_bound","category"]], left_on="value", right_on="lower_bound").drop("lower_bound", axis=1)
>>> output
id value category
0 id_1 20 B
1 id_2 500 D
2 id_3 1000 E
您可以使用 np.dot
:
vals = np.vstack(df['value'].values)
lb = condition['lower_bound'].values <= vals
ub = vals <= condition['upper_bound'].values
df['category'] = np.dot(lb & ub, condition['category'])
输出:
id | value | category |
---|---|---|
id_1 | 20 | B |
id_2 | 500 | D |
id_3 | 1000 | E |