当股票价格在彼此的0.5%之内时,将它们分组

时间:2010-01-25 04:32:30

标签: python list cluster-analysis grouping stocks

感谢您的回答,我之前没有使用过StackOverflow,因此我对答案的数量和速度感到惊讶 - 这太棒了。

我还没有正确理解答案,但我想我应该在问题规范中添加一些信息。见下图。

我无法在此发布图片,因为我没有足够的分数,但您可以看到图像 在http://journal.acquitane.com/2010-01-20/image003.jpg

此图片可能更贴切地描述我想要实现的目标。因此,您可以在整个页面的水平线上看到图表上的价格点。现在,您可以在每个0.5%的范围内获得线条聚类,这被认为是一件好事,为什么我想自动识别这些聚类。您可以在图表上看到S2& MR1,R2& WPP1。

所以我每天都会产生这些价位,然后我可以手动识别0.5%以内的价格。 - 但这个问题的目的是如何使用python例程。

我再次使用标签复制了这个列表(见下文)。请注意,列表价格点与图像中的价格点不匹配,因为它们来自两个不同的日期。

[YR3,175.24,8] [SR3,147.85,6] [YR2,144.13,8] [SR2,130.44,6] [YR1,127.79,8] [QR3,127.42,5] [SR1,120.94,6] [QR2,120.22,5] [MR3,118.10,3] [WR3,116.73,2] [DR3,116.23,1] [WR2,115.93,2] [QR1,115.83,5] [MR2,115.56,3] [DR2,115.53,1] [WR1,114.79,2] [DR1,114.59,1] [WPP,113.99,2] [DPP,113.89,1] [MR1,113.50,3] [DS1,112.95,1] [WS1,112.85,2] [DS2,112.25,1] [WS2,112.05,2] [DS3,111.31,1] [MPP,110.97,3] [WS3,110.91,2] [50MA,110.87,4] [MS1,108.91,3] [QPP,108.64,5] [MS2,106.37,3] [MS3,104.31,3] [QS1,104.25,5] [SPP,103.53,6] [200MA,99.42,7] [QS2,97.05,5] [YPP,96.68,8] [SS1,94.03,6] [QS3,92.66,5] [YS1,80.34,8] [SS2,76.62,6] [SS3,67.12,6] [YS2,49.23,8] [YS3,32.89,8]

我确实在原始列表中犯了一个错误,因为C组错了,不应该包括在内。感谢您指出了这一点。

0.5%也没有固定,这个值每天都会变化,但我只是用0.5%作为规范问题的例子。

再次感谢。 标记

PS。我现在就开始检查答案。

嗨:

我需要对股票价格进行一些操纵。我刚刚开始使用Python,(但我认为在任何语言中实现它都会遇到麻烦)。我正在寻找一些关于如何在python中很好地实现它的想法。

由于 标记

问题: 我有一个列表列表(FloorLevels(见下文)),其中子列表有两个项目(股票价格,权重)。我想将股票价格分成小组,当它们在彼此的0.5%之内时。团体力量将由其总重量决定。例如:

Group-A
115.93,2
115.83,5
115.56,3
115.53,1
-------------
TotalWeight:12
-------------
Group-B
113.50,3
112.95,1
112.85,2
-------------
TotalWeight:6
-------------    

FloorLevels[   
[175.24,8]
[147.85,6]
[144.13,8]
[130.44,6]
[127.79,8]
[127.42,5]
[120.94,6]
[120.22,5]
[118.10,3]
[116.73,2]
[116.23,1]
[115.93,2]
[115.83,5]
[115.56,3]
[115.53,1]
[114.79,2]
[114.59,1]
[113.99,2]
[113.89,1]
[113.50,3]
[112.95,1]
[112.85,2]
[112.25,1]
[112.05,2]
[111.31,1]
[110.97,3]
[110.91,2]
[110.87,4]
[108.91,3]
[108.64,5]
[106.37,3]
[104.31,3]
[104.25,5]
[103.53,6]
[99.42,7]
[97.05,5]
[96.68,8]
[94.03,6]
[92.66,5]
[80.34,8]
[76.62,6]
[67.12,6]
[49.23,8]
[32.89,8]
]

7 个答案:

答案 0 :(得分:3)

我建议重复使用k-means clustering - 让我们简称为KMC。 KMC是一种简单而强大的聚类算法......但它需要“被告知”您要瞄准的聚类数量k。你事先并不知道(如果我理解你的话) - 你只想要最小的k,这样两个项目“聚集在一起”就不会超过X%。所以,从k等于1开始 - 所有东西都聚集在一起,不需要聚类传递;-) - 并检查聚类的直径(聚类的“直径”,来自术语的使用在几何中,是群集中任何两个成员之间的最大距离。)

如果直径为> X%,请设置k += 1,使用k作为群集数执行KMC,然后迭代重复检查。

在伪代码中:

def markCluster(items, threshold):
    k = 1
    clusters = [items]
    maxdist = diameter(items)
    while maxdist > threshold:
        k += 1
        clusters = Kmc(items, k)
        maxdist = max(diameter(c) for c in clusters)
    return clusters

当然我们假设我们有合适的diameterKmc Python函数。

这听起来像你想要的那种吗?如果是这样,那么我们可以继续向您展示如何编写diameterKmc(如果您的items数量相对有限,则使用纯Python进行处理,否则可能会通过利用强大的第三方附加框架,例如numpy) - 但如果你真的想要一些非常不同的东西,那么就不值得去做这个问题了! - )

答案 1 :(得分:2)

如果s中的每个股票Gt * 1.05> = G,则股票s属于某个群组ts / 1.05< = t,对吧?

我们如何将股票添加到每个组?如果我们有股票95,100,101和105,我们开始一个100组,然后加101,我们将以{100,101,105}结束。如果我们在100之后做了95,我们最终得到{100,95}。

我们只需要考虑所有可能的排列吗?如果是这样,您的算法效率会很低。

答案 2 :(得分:2)

您需要更详细地指明您的问题。什么“当股票价格在彼此的0.5%之内时将它们分成小组”是什么意思?

的可能性:

(1)该组的每个成员都在该组的每个其他成员的0.5%之内

(2)对列表进行排序并将其拆分到差距大于0.5%

的位置

请注意,116.23在115.93 - abs((116.23 / 115.93 - 1) * 100) < 0.5的0.5%范围内 - 但您在A组中放了一个数字,在C组中放了一个。

简单示例:a, b, c = (0.996, 1, 1.004) ...请注意a和b适合,b和c适合,但a和c不适合。你希望他们如何分组,为什么?输入列表中的顺序是否相关?

可能性(1)产生ab,c或a,bc ......打破平局规则,请
可能性(2)产生abc(没有大的差距,所以只有一组)

答案 3 :(得分:1)

您将无法将其归类为“硬”群组。如果你有价格(1.0,1.05,1.1)那么第一个和第二个应该在同一个组中,第二个和第三个应该在同一个组中,而不是第一个和第三个。

快速,肮脏的方式做一些你可能会觉得有用的事情:

def make_group_function(tolerance = 0.05):
    from math import log10, floor
    # I forget why this works. 
    tolerance_factor = -1.0/(-log10(1.0 + tolerance))
    # well ... since you might ask
    # we want: log(x)*tf - log(x*(1+t))*tf = -1, 
    # so every 5% change has a different group. The minus is just so groups 
    # are ascending .. it looks a bit nicer.
    #
    # tf = -1/(log(x)-log(x*(1+t)))
    # tf = -1/(log(x/(x*(1+t))))
    # tf = -1/(log(1/(1*(1+t)))) # solved .. but let's just be more clever
    # tf = -1/(0-log(1*(1+t)))
    # tf = -1/(-log((1+t))
    def group_function(value):
        # don't just use int - it rounds up below zero, and down above zero
        return int(floor(log10(value)*tolerance_factor))
    return group_function

用法:

group_function = make_group_function()
import random
groups = {}
for i in range(50):
    v = random.random()*500+1000
    group = group_function(v)
    if group in groups:
        groups[group].append(v)
    else:
        groups[group] = [v]

for group in sorted(groups):
    print 'Group',group
    for v in sorted(groups[group]):
        print v
    print

答案 4 :(得分:0)

对于给定的一组股票价格,可能有多种方法可以将彼此相差0.5%的股票分组。如果没有一些额外的价格分组规则,就无法确定答案会做你真正想要的。

答案 5 :(得分:0)

除了选择哪些值组合在一起的正确方法之外,这是一个问题,其中一个小的面向对象落入可以使它更容易处理。

我在这里制作了两个课程,只有最少的理想行为,但是这可以使分类变得更容易 - 你可以在Group课程中单独使用它。

我可以看到下面的代码是不正确的,在某种意义上,随着新成员的添加,组包含的限制会有所不同 - 即使它与分离crieteria重新相同,你仍然可以使用get_groups方法来使用多遍做法。它应该很难 - 但代码太长了,无法在这里提供帮助,而且我认为这个剪辑是让你顺利进行的:

from copy import copy

class Group(object):
    def __init__(self,data=None, name=""):
        if data:
            self.data = data
        else:
            self.data = []
        self.name = name

    def get_mean_stock(self):
        return sum(item[0] for item in self.data) / len(self.data)

    def fits(self, item):
        if 0.995 < abs(item[0]) / self.get_mean_stock() < 1.005:
            return True
        return False

    def get_weight(self):
        return sum(item[1] for item in self.data)

    def __repr__(self):
        return "Group-%s\n%s\n---\nTotalWeight: %d\n\n" % (
            self.name,
            "\n".join("%.02f, %d" % tuple(item) for item in self.data ),
            self.get_weight())


class StockGrouper(object):
    def __init__(self, data=None):
        if data:
            self.floor_levels = data
        else:
            self.floor_levels = []

    def get_groups(self):
        groups = []
        floor_levels = copy(self.floor_levels)
        name_ord = ord("A") - 1
        while floor_levels:
            seed = floor_levels.pop(0)
            name_ord += 1
            group = Group([seed], chr(name_ord))
            groups.append(group)
            to_remove = []
            for i, item in enumerate(floor_levels):
                if group.fits(item):
                    group.data.append(item)
                    to_remove.append(i)
            for i in reversed(to_remove):
                floor_levels.pop(i)
        return groups

测试:

floor_levels = [  [stock. weight] ,... <paste the data above> ]
s = StockGrouper(floor_levels)
s.get_groups()

答案 6 :(得分:0)

对于分组元素,你能使用itertools.groupby()吗?在对数据进行排序时,已经完成了很多分组工作,然后您可以测试迭代中的当前值是否与最后一个值相差<0.5%,并将itertools.groupby()分解为每次函数返回false时都会有一个新组。