【问题标题】:Binning variable length lists in python在python中对可变长度列表进行分箱
【发布时间】:2016-02-25 21:47:22
【问题描述】:

我有一个字典 d 有 100 个键,其中的值是可变长度列表,例如

 In[165]: d.values()[0]
 Out[165]: 
 [0.0432,
  0.0336,
  0.0345,
  0.044,
  0.0394,
  0.0555]

 In[166]: d.values()[1]
 Out[166]: 
 [0.0236,
  0.0333,
  0.0571]

这就是我想做的事情:对于d.values() 中的每个列表,我想将值组织到 10 个 bin 中(如果一个值满足标准,则将其扔到一个 bin 中,例如介于 0.03 之间和 0.04、0.04 和 0.05 等)。

我希望得到的结果看起来与 d 完全一样,但不是 d.values()[0] 是一个数字列表,我希望它是一个列表列表,就像这样:

 In[167]: d.values()[0]
 Out[167]:
 [[0.0336,0.0345,0.0394],
  [0.0432,0.044],
  [0.0555]]

每个键仍将与相同的值相关联,但它们会被结构化到 10 个 bin 中。

我一直对嵌套的 for 循环和 if/else 等感到疯狂。解决此问题的最佳方法是什么?

编辑:大家好。只是想让你知道我解决了我的问题。我使用了@Brent Washburne 答案的变体。感谢您的帮助!

【问题讨论】:

  • 您的最后一个示例显示了以前未显示的In[167]Out[166],但似乎是来自165 的值,您能修改并澄清一下吗?另外,创建“垃圾箱”的逻辑是什么?您提到介于 0.03 和 0.04 之间,但实际上您所显示的数据都没有满足该标准。不清楚你在问什么......
  • 抱歉,我进行了编辑以修复输入/输出。垃圾箱的逻辑是我知道最小值和最大值(大致对应于 0 和 0.15)并且我想要 10 个垃圾箱。所以实际上,我想要宽度约为 0.015 的垃圾箱(很抱歉在原始帖子中没有明确说明。)另外,我不明白你为什么说我的数据不符合标准。例如,从 Input[165] 中,d.values()[0][0] 是一个介于 0.03 和 0.04 之间的值...
  • 您的输出包含多个超出分箱范围的值,例如 0.394 > 0.04 和 0.0555 > 0.04。那么,为什么要将这两个值与符合0.03 <= value <= 0.04 标准的值合并?
  • 啊,我真的很抱歉。我没有意识到我的输出如此混乱。我修好了。

标签: python dictionary binning


【解决方案1】:
def bin(values):
    bins = [[] for _ in range(10)]    # create ten bins
    for n in values:
        b = int(n * 100)              # normalize the value to the bin number
        bins[b].append(n)             # add the number to the bin
    return bins

d =  [0.0432,
  0.0336,
  0.0345,
  0.044,
  0.0394,
  0.0555]
print bin(d)

结果是:

[[], [], [], [0.0336, 0.0345, 0.0394], [0.0432, 0.044], [0.0555], [], [], [], []]

【讨论】:

  • 感谢您的回答!我喜欢编写函数的想法,但我可能需要使 bin 大小 b 具有不同的大小和宽度。例如,对于一个样本,我希望 bin 宽度为 0.015,最小值为 0,最大值为 0.15。这将如何改变b
  • 您可以除以 bin 宽度,而不是乘以 100:b = int(n / 0.015)
【解决方案2】:

您可以通过传递适当的键函数来使用itertools.groupby() 函数来对您的项目进行分类。在这种情况下,您可以使用 floor(x*100) 作为您的关键功能:

>>> from math import floor
>>> from itertools import groupby
>>> lst = [0.0432, 0.0336, 0.0345, 0.044, 0.0394, 0.0555]
>>> [list(g) for _,g in groupby(sorted(lst), key=lambda x: floor(x*100))]
[[0.0336, 0.0345, 0.0394], [0.0432, 0.044], [0.0555]]

为了将其应用于您的值,您可以使用字典理解:

def categorizer(val):
    return [list(g) for _,g in groupby(sorted(lst), key=lambda x: floor(x*100))]

new_dict = {k:categorizer(v) for k,v in old_dict.items()}

作为另一种在执行速度方面更优化的方法,您可以使用字典进行分类:

>>> def categorizer(val, d={}):
...     for i in val:
...         d.setdefault(floor(i*100),[]).append(i)
...     return d.values()

【讨论】:

  • 感谢您的回答!正如我在另一条评论中所说,对于一个数据样本,我想要范围为 0-0.15、宽度为 0.015 的箱。这如何改变按键功能?
【解决方案3】:

为什么不将值设置为一组字典,其中 ke 是 bin 指示符,而值是该 bin 中那些项目的列表?

你会定义

newd = [{bin1:[], bin2:[], ...binn:[]}, ... ]
newd[0][bin1] = (list of items in d[0] that belong in bin1)

您现在有一个字典列表,每个字典都有相应的 bin 列表。

newd[0] 现在相当于从d[0] 构建的字典,每个键(我称之为 bin1、bin2、... binn)都包含适合该 bin 的值列表。因此我们有`newd[0][bin1], newd[0][bin2, ... new[k][lastbin]

字典创建允许您在进行过程中创建适当的键和值列表。如果还没有特定的 bin 键,则创建空列表,然后将值追加到列表中。

现在,当您想要识别 bin 的元素时,您可以遍历 newd 列表并提取您想要的任何 bin。这允许您拥有没有条目的垃圾箱,而无需创建空列表。如果 bin 键不在 newd 中,则检索设置为默认返回一个空列表(以避免字典无效键异常)。

【讨论】:

  • 我认为这不足以适用于其他数据样本。另外,考虑到对于d 的任何元素,我必须在每个列表中迭代多达1000 个数据点,如何构造newd[0][bin1]?一般来说?
  • @Astrobeer3plus 我在答案中添加了一段应该解释我的意思。
猜你喜欢
  • 1970-01-01
  • 2017-10-19
  • 1970-01-01
  • 2018-08-30
  • 2017-12-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多