2010-01-25 3 views
0

Спасибо за ответы, я раньше не использовал StackOverflow, поэтому я был удивлен количеством ответов и скоростью их - ее фантастической.поместите акции в группы, когда они находятся в пределах 0,5% друг от друга

Я еще не прошел ответы, но подумал, что должен добавить некоторую информацию к спецификации проблемы. См. Изображение ниже.

Я не могу отправить изображение в этом, потому что я не достаточно очков, но вы можете увидеть изображение в 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] [ДПП , 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] [ МРР, 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] [ППМС, 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% в качестве примера для определения проблемы.

Еще раз спасибо. Mark

PS.Сейчас я начну проверять ответы.

Привет:

мне нужно сделать некоторые манипуляции с ценами на акции. Я только начал использовать Python (но я думаю, что мне будет сложно реализовать это на любом языке). Я ищу некоторые идеи о том, как это прекрасно реализовать в python.

Благодаря Марк

Проблема: У меня есть список списков (FloorLevels (см ниже)), где Подсписок имеет два элемента (StockPrice, вес). Я хочу поставить фондовые индексы в группы, когда они находятся в пределах 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] 
] 
+1

116,23 в группе C находится в пределах 0,5% от 115,93 в группе A - почему они находятся в разных группах? – Autoplectic

+0

Не могли бы вы обрезать данные образца чему-то (a) значимым и (b) не прокручивать? –

+0

@Автоплектический, вы правы - извините насчет путаницы. @ S.Lott. Извините, это немного сложно без контекста, я попытался добавить некоторый контекст с изображением. Извините за прокрутку данных, я положил в новый список, который завернут. – mark

ответ

3

Я предлагаю повторное использование k-means clustering - давайте назовем его КМК для краткости. KMC - простой и мощный алгоритм кластеризации ... но ему нужно «рассказать», сколько кластеров, k, вы стремитесь. Вы не знаете, что заранее (если я правильно вас понимаю) - вам просто нужен наименьший k, так что два элемента, «сгруппированные вместе», больше, чем X% друг от друга. Итак, начните с k равным 1 - все сгруппировано вместе, нет необходимости в кластеризации ;-) - и проверьте диаметр кластера («диаметр» кластера от использования термина в геометрии - это наибольшее расстояние между любые два члена кластера).

Если диаметр > X%, установить k += 1, выполнить KMC с k как количество кластеров, и повторить проверку, итеративно.

В псевдокоде:

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 

при условии, конечно, у нас есть подходящие diameter и Kmc функции Python.

Это похоже на то, что вы хотите? Если это так, то мы можем перейти к тому, чтобы показать вам, как писать diameter и Kmc (в чистом Python, если у вас есть относительно ограниченное число items для решения, в противном случае, возможно, используя мощные сторонние надстройки, такие как numpy) - но не стоит так беспокоиться, если на самом деле вы хотите что-то совсем другое, откуда эта проверка!)

+0

@Alex Martelli. Привет, Алекс: Мне это нравится, я думал, что это проблема кластеризации, и рассматривал алгоритмы кластеризации, прежде чем ставить этот вопрос. Я думаю, что это будет хорошо подходит, вы можете расширить функции Diameter и KMC, пожалуйста. – mark

+0

@mark, за исключением проблем оптимизации, 'диаметр (aset)' - это просто 'max (расстояние (a, b) для aset для b в aset)', для любого 'distance', который вы выбираете для определения. K-означает, что кластеризация OTOH требует больше кода, чем может быть разумно сжата здесь, я буду рад изложить это, если вы спросите по отдельному вопросу (но URL-адрес википедии, на который я указываю, уже довольно хорош, ум!). –

+0

ОК, еще раз спасибо. – mark

2

Фонда s принадлежат группе G, если для каждого запаса t в G, s * 1,05> = t и s/1,05 < = t, верно?

Как добавить акции в каждую группу? Если у нас есть запасы 95, 100, 101 и 105, и мы начнем группу с 100, затем добавим 101, мы получим {100, 101, 105}. Если бы мы сделали 95 после 100, мы получим {100, 95}.

Нужно ли рассматривать все возможные перестановки? Если это так, ваш алгоритм будет неэффективным.

+0

Да, кажется, проблема плохо определена. – Greg

+0

@Eli: Спасибо, нужно создать неизвестное количество групп, где каждый член группы находится в пределах 0,5% друг от друга. @Greg «Спасибо, я согласен, я могу видеть, что хочу, но у меня проблемы с тем, чтобы понять проблему в читабельном виде. – mark

2

Вам необходимо указать вашу проблему более подробно. То, что означает «положить запасы в группы, когда они находятся в пределах 0,5% друг от друга» означает?

Возможность:

(1) каждый член группы находится в пределах 0,5% от любого другого члена группы

(2) сортировка списка и разделить его, где зазор составляет более 0,5%

Обратите внимание, что 116,23 находится в пределах 0,5% от 115.93 - abs((116.23/115.93 - 1) * 100) < 0.5 - но вы поставили один номер в группе а и один в группе С.

Простой пример: a, b, c = (0.996, 1, 1.004) ... Обратите внимание, что и б прилегание , b и c fit, но a и cd не подходит. Как вы хотите, чтобы они сгруппировались и почему? Соответствует ли заказ в списке входных данных?

Возможность (1) производит AB, C или, Ьс ... ничей правило, пожалуйста
Возможности (2) производит а (нет больших зазоров, так что только одна группы)

+0

@John Machin: Джон спасибо. (1) это тот случай, когда я за ним. Группа C неверна - пожалуйста, проигнорируйте ее. Вот где ее бит беспорядочный, a, b, c должен быть в группе, даже если a, c не подходят, но они связаны между собой, находясь в пределах 0,5% от b. – mark

+0

@ mark: Вы говорите: (1) - это тот случай, который вы хотите (каждый член группы находится в пределах 0,5% от ** каждого ** другого члена группы), но затем вы говорите, что a, b, c должны быть в группе : это возможность (2), то есть каждый член группы находится в пределах 5% от ** некоторых ** участников (групп) группы - решите и отредактируйте свой вопрос, чтобы показать однозначно то, что вы хотите. –

0

Для данного набор цен на акции, возможно, существует более одного способа группировать акции, которые находятся в пределах 0,5% друг от друга. Без каких-либо дополнительных правил для группировки цен нет никакого способа убедиться, что ответ будет делать то, что вы действительно хотите.

+0

@ Chris, Спасибо, это список ценовых точек для одного запаса. У меня нет никаких дополнительных правил - только правило о 0,5%. Но в любом случае кажется, что проблема падает s в проблему типа кластеризации, поэтому я склоняюсь к решению Alex Martellis выше. – mark

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 
+0

@wisty, Спасибо, на самом деле первый, второй и третий должны быть в группе, вот где это немного грязно. Несмотря на то, что третий и первый не находятся в пределах 0,5%, они связаны тем, что оба находятся в пределах 0,5% секунды. – mark

0

кроме надлежащего способа выбрать, какие значения подходят друг другу, это проблема, когда небольшая ориентация объекта возможно, с ним справится намного легче.

Я сделал здесь два класса с минимальным желаемым поведением, но который может сделать классификацию намного проще - вы получите одну точку, чтобы играть с ней в классе группы.

Я вижу, что приведенный ниже код неверен, в том смысле, что лимиты для группового включения варьируются по мере добавления новых членов - даже если это разделение crieteria remaisn одинаково, вы можете заставить метод get_groups использовать мульти- подход. Это должно Nto быть трудно - но код был бы слишком долго, чтобы быть полезным здесь, и я думаю, что это пропущено является enoguh, чтобы ты:

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() 
+0

@jsbeuno, Спасибо за ваши усилия, в этот момент я склоняюсь к кластерному решению Alex Martelli. – mark

0

Для группировки элемент, можно ли использовать itertools.groupby()? По мере сортировки данных большая часть работы по группировке уже выполнена, и тогда вы можете проверить, было ли текущее значение в итерации отличным от последнего на < 0,5%, и itertools.groupby() разбивается на новая группа каждый раз, когда ваша функция возвращает false.

+0

@yorksranter: Спасибо, я не знаком с itertools.groupby(). На данный момент я думаю, что решение Alex Martelli с использованием алгоритма кластеризации выглядит хорошо. – mark

Смежные вопросы