2010-06-10 3 views
6

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

  • максимальное количество строк. Например, ограничивая список из 1234 записей до 1000.
  • Доля исходных строк. Например, сделав список 1/3 его первоначальной длины.

(Мне нужно иметь возможность выполнять оба способа, но только один используется одновременно).

Я считаю, что для максимального числа строк я могу просто вычислить пропорцию необходимой и передать пропорциональное downsizer:

def downsample_to_max(self, rows, max_rows): 
     return downsample_to_proportion(rows, max_rows/float(len(rows))) 

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

EDIT: Список содержит объекты, а не числовые значения, поэтому мне не нужно интерполировать. Удаление объектов в порядке.

РЕШЕНИЕ:

def downsample_to_proportion(self, rows, proportion): 

    counter = 0.0 
    last_counter = None 
    results = [] 

    for row in rows: 

     counter += proportion 

     if int(counter) != last_counter: 
      results.append(row) 
      last_counter = int(counter) 

    return results 

Спасибо.

ответ

0

Держите счетчик, который вы увеличиваете на второе значение. Положите его каждый раз и получите значение по этому индексу.

+0

Прошу, пожалуйста, немного уточнить? Благодарю. – Dave

+0

Начните с счетчика в 0. Пока счетчик меньше длины списка: введите элемент списка, индекс которого является значением счетчика, настил, затем увеличивайте счетчик. –

6

Вы можете использовать islice из itertools:

from itertools import islice 

def downsample_to_proportion(rows, proportion=1): 
    return list(islice(rows, 0, len(rows), int(1/proportion))) 

Использование:

x = range(1,10) 
print downsample_to_proportion(x, 0.3) 
# [1, 4, 7] 
3

Вместо islice() + list() более эффективно использовать синтаксис ломтика непосредственно, если вход уже тип последовательности:

def downsample_to_proportion(rows, proportion): 
    return rows[::int(1/proportion)] 
0

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

Это немного длинный (около 90 строк), но если вам эта потребность нужна, вам нужен простой в использовании oneliner и нужна среда с чистой зависимостью на основе Python, тогда я считаю, что это может быть полезно.

В принципе, единственное, что вам нужно сделать, это передать список функции и сказать ему, какой длины вы хотите, чтобы ваш новый список будет, а функция будет либо:

  • сократить список путем удаления элементов, если новая длина меньше, как и предыдущие ответы.
  • стрейч/высококлассные ваш список (противоположность разукрупнения), если новая длина больше, с дополнительной опцией, вы можете решить, следует ли: линейно
    • интерполировать м.т. известных значений (выбирается автоматически, если список содержит Интс или поплавки)
    • дублируют каждое значение, таким образом они занимают пропорциональный размер нового списка (выбирается автоматически, если список содержит не-числа)
    • дергать исходные значения друг от друга и оставить пробелы между

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

Например, вы можете сказать:

origlist = [0,None,None,30,None,50,60,70,None,None,100] 
resizedlist = ResizeList(testlist, 21) 
print(resizedlist) 

и получить

[0, 5.00000000001, 9.9999999999900009, 15.0, 20.000000000010001, 24.999999999989999, 30, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0, 65.0, 70, 75.000000000010004, 79.999999999989996, 85.0, 90.000000000010004, 94.999999999989996, 100] 

Обратите внимание, что незначительные неточности будут возникать из-за ограничений с плавающей точкой. Кроме того, я написал это для Python 2.x, поэтому, чтобы использовать его на Python 3.x, просто добавьте одну строку, которая говорит xrange = range.

И вот отличный способ интерполировать между позиционируемыми подэлементами в списке списков. Так, например, вы можете легко интерполировать между цветовыми кортежами RGB, чтобы создать градиент цвета x nr шагов. Предполагая, что список RGB цветовых наборов 3 и желаемой переменной GRADIENTLENGTH вы делаете это с:

crosssections = zip(*rgbtuples) 
grad_crosssections = (ResizeList(spectrum,GRADIENTLENGTH) for spectrum in crosssections) 
rgb_gradient = [list(each) for each in zip(*grad_crosssections)] 

Это, вероятно, может понадобиться довольно много оптимизаций, я должен был сделать совсем немного экспериментов. Если вы чувствуете, что можете улучшить, не стесняйтесь редактировать мой пост. Вот код:

def ResizeList(rows, newlength, stretchmethod="not specified", gapvalue=None): 
    """ 
    Resizes (up or down) and returns a new list of a given size, based on an input list. 
    - rows: the input list, which can contain any type of value or item (except if using the interpolate stretchmethod which requires floats or ints only) 
    - newlength: the new length of the output list (if this is the same as the input list then the original list will be returned immediately) 
    - stretchmethod: if the list is being stretched, this decides how to do it. Valid values are: 
     - 'interpolate' 
     - linearly interpolate between the known values (automatically chosen if list contains ints or floats) 
     - 'duplicate' 
     - duplicate each value so they occupy a proportional size of the new list (automatically chosen if the list contains non-numbers) 
     - 'spread' 
     - drags the original values apart and leaves gaps as defined by the gapvalue option 
    - gapvalue: a value that will be used as gaps to fill in between the original values when using the 'spread' stretchmethod 
    """ 
    #return input as is if no difference in length 
    if newlength == len(rows): 
     return rows 
    #set auto stretchmode 
    if stretchmethod == "not specified": 
     if isinstance(rows[0], (int,float)): 
      stretchmethod = "interpolate" 
     else: 
      stretchmethod = "duplicate" 
    #reduce newlength 
    newlength -= 1 
    #assign first value 
    outlist = [rows[0]] 
    writinggapsflag = False 
    if rows[1] == gapvalue: 
     writinggapsflag = True 
    relspreadindexgen = (index/float(len(rows)-1) for index in xrange(1,len(rows))) #warning a little hacky by skipping first index cus is assigned auto 
    relspreadindex = next(relspreadindexgen) 
    spreadflag = False 
    gapcount = 0 
    for outlistindex in xrange(1, newlength): 
     #relative positions 
     rel = outlistindex/float(newlength) 
     relindex = (len(rows)-1) * rel 
     basenr,decimals = str(relindex).split(".") 
     relbwindex = float("0."+decimals) 
     #determine equivalent value 
     if stretchmethod=="interpolate": 
      #test for gap 
      maybecurrelval = rows[int(relindex)] 
      maybenextrelval = rows[int(relindex)+1] 
      if maybecurrelval == gapvalue: 
       #found gapvalue, so skipping and waiting for valid value to interpolate and add to outlist 
       gapcount += 1 
       continue 
      #test whether to interpolate for previous gaps 
      if gapcount > 0: 
       #found a valid value after skipping gapvalues so this is where it interpolates all of them from last valid value to this one 
       startvalue = outlist[-1] 
       endindex = int(relindex) 
       endvalue = rows[endindex] 
       gapstointerpolate = gapcount 
       allinterpolatedgaps = Resize([startvalue,endvalue],gapstointerpolate+3) 
       outlist.extend(allinterpolatedgaps[1:-1]) 
       gapcount = 0 
       writinggapsflag = False 
      #interpolate value 
      currelval = rows[int(relindex)] 
      lookahead = 1 
      nextrelval = rows[int(relindex)+lookahead] 
      if nextrelval == gapvalue: 
       if writinggapsflag: 
        continue 
       relbwval = currelval 
       writinggapsflag = True 
      else: 
       relbwval = currelval + (nextrelval - currelval) * relbwindex #basenr pluss interindex percent interpolation of diff to next item 
     elif stretchmethod=="duplicate": 
      relbwval = rows[int(round(relindex))] #no interpolation possible, so just copy each time 
     elif stretchmethod=="spread": 
      if rel >= relspreadindex: 
       spreadindex = int(len(rows)*relspreadindex) 
       relbwval = rows[spreadindex] #spread values further apart so as to leave gaps in between 
       relspreadindex = next(relspreadindexgen) 
      else: 
       relbwval = gapvalue 
     #assign each value 
     outlist.append(relbwval) 
    #assign last value 
    if gapcount > 0: 
     #this last value also has to interpolate for previous gaps  
     startvalue = outlist[-1] 
     endvalue = rows[-1] 
     gapstointerpolate = gapcount 
     allinterpolatedgaps = Resize([startvalue,endvalue],gapstointerpolate+3) 
     outlist.extend(allinterpolatedgaps[1:-1]) 
     outlist.append(rows[-1]) 
     gapcount = 0 
     writinggapsflag = False 
    else: 
     outlist.append(rows[-1]) 
    return outlist