使用数字之间的相对关系对Python中的数字进行分组/聚类

时间:2019-04-25 08:24:00

标签: python numbers

我需要的东西与询问的here类似,但反之则更多:

给出一个数字列表(来自上述问题的示例):[1、6、9、100、102、105、109、134、139]我不想说最大差距(在该示例中为10)但是我想要几个小组。

例如 3组:1、6、9 / 100、102、105、109 / 134、139 2组:1、6、9 / 100、102、105、109、134、139 ...

这应该是相对的,因为我的数字非常非常不同: [0.1,0.2,1,4,100,110] => 3组应得出0.1、0.2 / 1、4 / 100、110

尽管0.2和1在绝对值上分别比1和5(0.8对3)更近,而0.2与1(5倍)比0.1(2x)更远。

我希望我能以某种方式弄清楚我想要实现的目标...

2 个答案:

答案 0 :(得分:0)

import sys

# Sorted numbers.
xs = [0.1, 0.2, 1, 4, 100, 110]
xs.sort()

# Reverse-sorted (RATIO, INDEX) tuples.
tups = sorted(
    (
        (xs[i] / xs[i - 1] if i else 0, i)
        for i, x in enumerate(xs)
    ),
    reverse = True,
)

# Indexes of the boundaries having the largest ratios.
n_groups = int(sys.argv[1])
boundaries = sorted(tup[1] for tup in tups[0 : n_groups - 1])
boundaries.append(None)

# Create the groups, based on those boundaries.
groups = []
i = 0
for j in boundaries:
    groups.append(xs[i:j])
    i = j

# Check.
for g in groups:
    print(g)

示例输出:

# n_groups = 1
[0.1, 0.2, 1, 4, 100, 110]

# n_groups = 2
[0.1, 0.2, 1, 4]
[100, 110]

# n_groups = 3
[0.1, 0.2]
[1, 4]
[100, 110]

# n_groups = 4
[0.1, 0.2]
[1]
[4]
[100, 110]

# n_groups = 5
[0.1]
[0.2]
[1]
[4]
[100, 110]

答案 1 :(得分:0)

如果数字列表不是巨大,则我将首先计算数字与其先例之间的每个比率,然后选择最大的拆分。

例如:

def split_numbers_list(numbers_list, n_groups):
    # If the number of groups is 1 or less, the whole list the only group
    if n_groups <= 1:
        return [numbers_list]
    n_splits = min(len(numbers_list), n_groups) # Can't have more groups than elements
    # Now we calculate the ratios and store them in (index, ratio) tuples
    ratios = [
        (i, numbers_list[i + 1] / numbers_list[i]) for i in range(len(numbers_list) - 1)
    ]
    sorted_ratios = sorted(ratios, key=lambda r: r[1], reverse=True)
    # `chosen_splits` stores the boundaries of each group
    chosen_splits = (
        [0]
        + sorted([r[0] + 1 for r in sorted_ratios[: n_splits - 1]])
        + [len(numbers_list)]
    )
    return [
        numbers_list[chosen_splits[i] : chosen_splits[i + 1]]
        for i in range(len(chosen_splits) - 1)
    ]

但是请注意numbers_list的含义:它必须是严格正数数字的排序列表,否则此功能将不起作用。

一些例子:

>>> my_list = [1, 2, 3, 4, 5, 100, 101, 103, 504, 2301]

>>> split_numbers_list(my_list, 5)
[[1], [2, 3, 4, 5], [100, 101, 103], [504], [2301]]

>>> split_numbers_list(my_list, 3)
[[1, 2, 3, 4, 5], [100, 101, 103], [504, 2301]]