Domanda

Ho una lista Python con un numero di voci, che ho bisogno di downsample utilizzando:

  • Un numero massimo di righe. Ad esempio, limitando l'elenco delle voci 1234 e 1000.
  • Una parte delle righe originali. Ad esempio, facendo la lista 1/3 della sua lunghezza originale.

(Ho bisogno di essere in grado di fare entrambe le direzioni, ma solo uno viene utilizzato per volta).

Credo che per il numero massimo di righe che posso solo calcolare la proporzione necessaria e passa che al Downsizer proporzionale:

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

... quindi ho davvero bisogno di una sola funzione downsampling. Eventuali suggerimenti, per favore?

Modifica La lista contiene oggetti, non i valori numerici quindi non ho bisogno di interpolare. La caduta di oggetti va bene.

SOLUZIONE:

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

Grazie.

È stato utile?

Soluzione

Mantenere un contatore, che si incrementa con il secondo valore. Pavimento ogni volta, e fornire il valore a tale indice.

Altri suggerimenti

È possibile utilizzare islice da itertools:

from itertools import islice

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

Utilizzo:

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

Invece di islice() + list() è più efficiente utilizzare la sintassi slice direttamente se l'ingresso è già un tipo di sequenza:

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

Questa soluzione potrebbe essere un po 'eccessivo per il manifesto originale, ma ho pensato di condividere il codice che ho usato per risolvere questo e simili problemi.

E 'un po' lungo (circa 90 righe), ma se si ha spesso questa esigenza, vogliono un oneliner facile da usare, e hanno bisogno di un ambiente privo di dipendenza puro-Python, allora mi sa che potrebbe essere utile.

In sostanza, l'unica cosa che dovete fare è passare la vostra lista per la funzione e indicare cosa lunghezza si desidera che il nuovo elenco di essere, e la funzione di due operazioni:

  • downsize l'elenco facendo cadere oggetti se la nuova lunghezza è più piccolo, molto simile alle risposte precedenti già suggerito.
  • tratto / alto livello la vostra lista (l'opposto di downsizing) se la nuova lunghezza è più grande, con l'opzione aggiuntiva che si può decidere se:
    • linearmente interpolare bw i valori noti (scelti automaticamente se elenco contiene interi o galleggianti)
    • duplicare ogni valore in modo che occupano una dimensione proporzionale della nuova lista (scelto automaticamente se l'elenco contiene i non-numeri)
    • tirare i valori originali a parte e le lacune congedo tra

Il tutto viene raccolto all'interno di una funzione, quindi se avete bisogno basta copiare e incollare al vostro script e si può iniziare ad usarlo subito.

Per esempio si potrebbe dire:

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

e get

[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]

Si noti che lievi imprecisioni potranno verificarsi a causa di limitazioni virgola mobile. Inoltre, ho scritto questo per Python 2.x, quindi usarlo su Python 3.x è sufficiente aggiungere una sola riga che dice xrange = range.

E qui è un trucco ingegnoso per interpolare tra elementi secondari posizionati in una lista di liste. Così, per esempio, si può facilmente interpolare tra tuple di colore RGB per creare una sfumatura di colore di x n di passi. Assumendo una lista di tuple RGB a colori di 3 e una variabile GRADIENTLENGTH desiderato si esegue questa operazione con:

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

Probabilmente potrebbe avere bisogno di un bel paio di ottimizzazioni, ho dovuto fare un po 'di sperimentazione. Se vi sentite in grado di migliorare si sente libero di modificarla mio post. Ecco il codice:

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

Impossibile random.choices () risolvere il problema? Altri esempi sono disponibili qui

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top