具有多个条件的 Numpy“where”
- 2025-02-07 14:32:00
- admin 原创
- 62
问题描述:
我尝试在数据框“df_energy”中添加一个新列“energy_class”,如果“consumption_energy”值> 400,则包含字符串“high”,如果“consumption_energy”值在 200 到 400 之间,则包含字符串“medium”,如果“consumption_energy”值低于 200,则包含字符串“low”。我尝试 np.where
从 numpy 中使用,但我发现numpy.where(condition[, x, y])
它只处理两个条件,而不是像我的情况那样处理 3 个。
解决方案 1:
尝试一下:使用@Maxu 的设置
col = 'consumption_energy'
conditions = [ df2[col] >= 400, (df2[col] < 400) & (df2[col]> 200), df2[col] <= 200 ]
choices = [ "high", 'medium', 'low' ]
df2["energy_class"] = np.select(conditions, choices, default=np.nan)
consumption_energy energy_class
0 459 high
1 416 high
2 186 low
3 250 medium
4 411 high
5 210 medium
6 343 medium
7 328 medium
8 208 medium
9 223 medium
解决方案 2:
您可以使用三元:
np.where(consumption_energy > 400, 'high',
(np.where(consumption_energy < 200, 'low', 'medium')))
解决方案 3:
我喜欢保持代码整洁。这就是我更喜欢np.vectorize
做这类任务的原因。
def conditions(x):
if x > 400: return "High"
elif x > 200: return "Medium"
else: return "Low"
func = np.vectorize(conditions)
energy_class = func(df_energy["consumption_energy"])
然后只需使用以下命令将 numpy 数组添加为数据框中的一列:
df_energy["energy_class"] = energy_class
这种方法的优点是,如果您希望向列添加更复杂的约束,可以轻松完成。希望对您有所帮助。
解决方案 4:
我将在这里使用cut()方法,它将生成非常高效且节省内存的category
dtype:
In [124]: df
Out[124]:
consumption_energy
0 459
1 416
2 186
3 250
4 411
5 210
6 343
7 328
8 208
9 223
In [125]: pd.cut(df.consumption_energy,
[0, 200, 400, np.inf],
labels=['low','medium','high']
)
Out[125]:
0 high
1 high
2 low
3 medium
4 high
5 medium
6 medium
7 medium
8 medium
9 medium
Name: consumption_energy, dtype: category
Categories (3, object): [low < medium < high]
解决方案 5:
让我们首先创建一个1000000
包含 和 之间的随机数的数据框0
,1000
用作测试
df_energy = pd.DataFrame({'consumption_energy': np.random.randint(0, 1000, 1000000)})
[Out]:
consumption_energy
0 683
1 893
2 545
3 13
4 768
5 385
6 644
7 551
8 572
9 822
对数据框的一些描述
print(df.energy.describe())
[Out]:
consumption_energy
count 1000000.000000
mean 499.648532
std 288.600140
min 0.000000
25% 250.000000
50% 499.000000
75% 750.000000
max 999.000000
有多种方法可以实现这一点,例如:
使用
numpy.where
df_energy['energy_class'] = np.where(df_energy['consumption_energy'] > 400, 'high', np.where(df_energy['consumption_energy'] > 200, 'medium', 'low'))
使用
numpy.select
df_energy['energy_class'] = np.select([df_energy['consumption_energy'] > 400, df_energy['consumption_energy'] > 200], ['high', 'medium'], default='low')
使用
numpy.vectorize
df_energy['energy_class'] = np.vectorize(lambda x: 'high' if x > 400 else ('medium' if x > 200 else 'low'))(df_energy['consumption_energy'])
使用
pandas.cut
df_energy['energy_class'] = pd.cut(df_energy['consumption_energy'], bins=[0, 200, 400, 1000], labels=['low', 'medium', 'high'])
使用 Python 的内置模块
def energy_class(x):
if x > 400:
return 'high'
elif x > 200:
return 'medium'
else:
return 'low'
df_energy['energy_class'] = df_energy['consumption_energy'].apply(energy_class)
使用 lambda 函数
df_energy['energy_class'] = df_energy['consumption_energy'].apply(lambda x: 'high' if x > 400 else ('medium' if x > 200 else 'low'))
时间比较
从我做过的所有测试来看,通过测量时间time.perf_counter()
(有关测量执行时间的其他方法,请参阅此处)pandas.cut
是最快的方法。
method time
0 np.where() 0.124139
1 np.select() 0.155879
2 numpy.vectorize() 0.452789
3 pandas.cut() 0.046143
4 Python's built-in functions 0.138021
5 lambda function 0.19081
笔记:
有关和的区别
pandas.cut
,pandas.qcut
请参见:pandas.qcut 和 pandas.cut 有什么区别?
解决方案 6:
警告:小心使用 NaN
请务必小心,如果您的数据有缺失值,np.where
则使用起来可能会很棘手,并且可能会无意中给您错误的结果。
考虑以下情况:
df['cons_ener_cat'] = np.where(df.consumption_energy > 400, 'high',
(np.where(df.consumption_energy < 200, 'low', 'medium')))
# if we do not use this second line, then
# if consumption energy is missing it would be shown medium, which is WRONG.
df.loc[df.consumption_energy.isnull(), 'cons_ener_cat'] = np.nan
或者,您可以使用 one-more 嵌套np.where
来表示 medium 与 nan,这样会很丑陋。
我认为最好的方法是pd.cut
。它处理 NaN 并且易于使用。
例子:
import numpy as np
import pandas as pd
import seaborn as sns
df = sns.load_dataset('titanic')
# pd.cut
df['age_cat'] = pd.cut(df.age, [0, 20, 60, np.inf], labels=['child','medium','old'])
# manually add another line for nans
df['age_cat2'] = np.where(df.age > 60, 'old', (np.where(df.age <20, 'child', 'medium')))
df.loc[df.age.isnull(), 'age_cat'] = np.nan
# multiple nested where
df['age_cat3'] = np.where(df.age > 60, 'old',
(np.where(df.age <20, 'child',
np.where(df.age.isnull(), np.nan, 'medium'))))
# outptus
print(df[['age','age_cat','age_cat2','age_cat3']].head(7))
age age_cat age_cat2 age_cat3
0 22.0 medium medium medium
1 38.0 medium medium medium
2 26.0 medium medium medium
3 35.0 medium medium medium
4 35.0 medium medium medium
5 NaN NaN medium nan
6 54.0 medium medium medium
解决方案 7:
试试这个:即使consumption_energy
包含空值也不要担心。
def egy_class(x):
'''
This function assigns classes as per the energy consumed.
'''
return ('high' if x>400 else
'low' if x<200 else 'medium')
chk = df_energy.consumption_energy.notnull()
df_energy['energy_class'] = df_energy.consumption_energy[chk].apply(egy_class)
解决方案 8:
我支持使用 np.vectorize。它比 np.where 快得多,而且代码也更简洁。使用更大的数据集,你绝对可以发现速度加快了。你可以对条件以及这些条件的输出使用字典格式。
# Vectorizing with numpy
row_dic = {'Condition1':'high',
'Condition2':'medium',
'Condition3':'low',
'Condition4':'lowest'}
def Conditions(dfSeries_element,dictionary):
'''
dfSeries_element is an element from df_series
dictionary: is the dictionary of your conditions with their outcome
'''
if dfSeries_element in dictionary.keys():
return dictionary[dfSeries]
def VectorizeConditions():
func = np.vectorize(Conditions)
result_vector = func(df['Series'],row_dic)
df['new_Series'] = result_vector
# running the below function will apply multi conditional formatting to your df
VectorizeConditions()
解决方案 9:
myassign["assign3"]=np.where(myassign["points"]>90,"genius",(np.where((myassign["points"]>50) & (myassign["points"]<90),"good","bad"))
当您只想使用“where”方法但有多个条件时。我们可以通过像上面一样的方法添加更多(np.where)来添加更多条件。同样,最后两个就是您想要的。