我试图找到一种方法,根据变量所在的位置来指定一个数值。即:
variable = 23
if variable < -100:
return_value = -15
elif variable <= -5:
return_value = -4
elif variable <= 5:
return_value = 18
else:
return_value = 88
当然,我可以创建一个包含buckets/values的列表,并在找到正确的值时迭代并返回:
bucket_values = [(-100, -15), (-5, -4), (5, 18)]
default = 88
variable = 100
for lower_bound, value in bucket_values:
if variable < lower_bound:
return_value = value
break
else:
return_value = default
但是,我需要检查下限和上限以及相等性,即,如果它是循环的第一次迭代,我必须检查是否是下一个循环(
我在找这样的东西(红宝石):
buckets = [
[:
[:<=, 5, -10],
[:<=, 10, 3],
[:>, 60, 40]]
# Pass bucket to a method
我的问题是:是否有一种方法可以通过变量边界和值来实现这一点?
我不确定这个问题的好题目是什么。欢迎任何建议。
检查这个答案…我不知道这是不是你要找的
您首先想到的代码是什么?如果你能把这个添加到问题中,W可以帮助你把它转换成python。
@安沃维奇,我不想找其他的。因为这会迫使桶的数量增加。
@Ruby i中的TobiasWilfert也可以这样做:buckets=[:,60,40]],然后将其传递给一个方法。在python中有类似的东西吗?
如果在您的问题中编写精确的Ruby等价物,那么在python中找到类似的东西可能会更容易,您的数字是否只是整数,或者它们也可以是浮点数?
@在我的例子中,只取整数。我编辑了我的问题来添加红宝石桶。
这被称为binning,有许多现有的解决方案。你能用pandas库吗?它有pd.cut()库吗?大熊猫的分田改造
@据我所知,smci pd.cut()将分为容器,但我看不到下限和上限,即如果我创建容器[0、10、20],它将创建2个容器[0-10]和[10-20],但没有用于说[-inf-0]或[20-inf]。如果我错了,我会更进一步。但这正是我想要的答案!
@Jubonn:通常情况下是相邻的独立垃圾箱,因此垃圾箱的顶部(n-1)是垃圾箱的底部,但您需要不相交的垃圾箱。您也可以包括丢失的箱,然后将非法/丢失的箱值映射到您想要的任何内容。btw、np.ninf、np.pinf是合法的bin值。
@smci这是我要找的答案!因此pd和np.ninf/np.inf的组合。
您想要一个基本的python解决方案(使用operator.ge/gt/lt/le)还是一个pandas+numpy解决方案(使用pd.cut),或者不关心哪个?您希望您的输出是包含bin的底值,还是与bin的编号相对应的分类值,或者您不在乎哪个?
@SMCI将与代码库的其他部分进行验证。不想添加太多依赖项。我认为这两个都是我问题的正确答案。
使用模块operator非常简单。下面是一个例子:
>>> import operator
>>> bucket = (operator.ge, -100, operator.le, -5)
>>> def in_bucket(value, bucket): return bucket[0](value, bucket[1]) and bucket[2](value, bucket[3])
...
>>> in_bucket(-101, bucket)
False
>>> in_bucket(-100, bucket)
True
>>> in_bucket(-5, bucket)
True
>>> in_bucket(-4, bucket)
False
但是,通过定义更通用的结构,您可以做得更好:
>>> conditions = ((operator.ge, -100), (operator.le, -5))
>>> def match_conditions(value, conditions): return all(c[0](value, c[1]) for c in conditions)
...
>>> match_conditions(-101, conditions)
False
>>> match_conditions(-100, conditions)
True
>>> match_conditions(-5, conditions)
True
>>> match_conditions(-4, conditions)
False
当满足所有条件时,all运算符返回真值。bucket和conditions的关键区别在于,可以添加不涉及边界的条件,例如,值必须成对:
>>> conditions = ((operator.ge, -100), (operator.le, -5), (lambda v, _: v%2==0, None))
>>> match_conditions(-7, conditions)
False
>>> match_conditions(-6, conditions)
True
>>> match_conditions(-5, conditions)
False
现在,您可以使用字典来总结您的条件(您给出的第一个示例):
>>> value_by_conditions = {
... ((operator.lt, -100),): -15,
... ((operator.ge, -100), (operator.le, -5)): -4,
... ((operator.gt, -5), (operator.le, 5)): 18,
... ((operator.gt, 5),): 88,
... }
>>> next((v for cs, v in value_by_conditions.items() if match_conditions(23, cs)), None)
88
>>> next((v for cs, v in value_by_conditions.items() if match_conditions(-101, cs)), None)
-15
>>> next((v for cs, v in value_by_conditions.items() if match_conditions(-100, cs)), None)
-4
笔记:
我使用元组,因为列表不可哈希(因此不能用作dict键);
next((x for x in xs if ), None)取xs中通过测试的第一个元素。如果没有元素通过测试,则返回默认值None;
在旧版本的python(<3.7)中,您不能保证测试的顺序。如果你有重叠的条件,这很重要。
这显然是次优的,因为您测试的是value < 100,还是value >= 100等。
这真的是Python吗?我不太确定。请浏览https://www.python.org/dev/peps/pep-0020/了解您的想法。
如果我理解你的话,对于每一个"桶",你都有一个间隔。要检查值是否属于某个间隔,可以定义一个函数:
def check_value(value, interval):
if value in range(interval[0], interval[1]+1):
print('Value ', value)
print('Interval ', interval)
else:
pass
现在,只需迭代一系列间隔来查找值所属的位置:
for interval in list_of_intervals:
check_value(value, interval)
这相当于@smci提到的pd.cut()函数。它不包括上下限。
我觉得这是相当不错的Python,但我不推荐它
>>> variable = 23
>>> return_value = -5 if variable
>>> print(return_value)
88
注意,88是默认值。编辑
您可以创建一个基于与上面显示的if... else相同概念的函数。函数如下所示:
def pythonic(variable, bucket_values, default):
for k,v in bucket_values:
return_value = v if variable
if return_value !="---":
return return_value
return default
你可以这样使用它:
>>> variable = 23
>>> bucket_values = [(-100, -15), (-5, -4), (5, 18)]
>>> print(pythonic(variable, bucket_values, 88))
88
>>> variable = 1
>>> print(pythonic(variable, bucket_values, 88))
18
我正在寻找一种可变值和边界的方法。因此,如果其他人不适合我。
@朱邦,我编辑了我的答案,希望这对你有用:)