2010-06-10 14 views
6

tôi có một danh sách Python với một số mục, mà tôi cần phải downsample sử dụng một trong hai:downsampling số lượng các mục trong một danh sách (mà không cần suy)

  • Một số lượng tối đa hàng. Ví dụ: giới hạn danh sách 1234 mục nhập thành 1000.
  • Tỷ lệ của các hàng gốc. Ví dụ: tạo danh sách 1/3 độ dài ban đầu của nó.

(Tôi cần có thể thực hiện cả hai cách, nhưng chỉ có một cách được sử dụng tại một thời điểm).

Tôi tin rằng đối với số lượng tối đa hàng tôi chỉ có thể tính toán tỷ lệ cần thiết và thông qua đó để các downsizer tỷ lệ:

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

... vì vậy tôi thực sự chỉ cần một chức năng downsampling. Bất kỳ gợi ý, xin vui lòng?

EDIT: Danh sách chứa đối tượng, không phải giá trị số vì vậy tôi không cần phải nội suy. Rơi đồ vật là tốt.

SOLUTION:

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 

Cảm ơn.

Trả lời

0

Giữ bộ đếm mà bạn tăng theo giá trị thứ hai. Lát nó mỗi lần và mang lại giá trị tại chỉ mục đó.

+0

Bạn có thể xây dựng một chút không? Cảm ơn. – Dave

+0

Bắt đầu với bộ đếm ở 0. Trong khi bộ đếm nhỏ hơn độ dài của danh sách: cho ra phần tử của danh sách có chỉ mục là giá trị của bộ đếm, được làm sàn, rồi tăng bộ đếm. –

6

Bạn có thể sử dụng islice từ itertools:

from itertools import islice 

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

Cách sử dụng:

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

Thay vì islice() + list() nó là hiệu quả hơn để sử dụng cú pháp lát trực tiếp nếu đầu vào đã là một loại trình tự:

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

Giải pháp này có thể hơi quá mức đối với áp phích gốc, nhưng tôi nghĩ tôi sẽ chia sẻ mã mà tôi đã sử dụng để giải quyết vấn đề này và các vấn đề tương tự.

Đó là một chút dài (khoảng 90 dòng), nhưng nếu bạn thường có nhu cầu này, muốn sử dụng trực tuyến dễ sử dụng và cần môi trường miễn phí tinh khiết Python, thì tôi cho rằng nó có thể được sử dụng.

Về cơ bản, điều duy nhất bạn phải làm là vượt qua danh sách của bạn với chức năng và nói với nó dài những gì bạn muốn danh sách mới của bạn được, và các chức năng sẽ hoặc là:

  • giảm bớt danh sách của bạn bằng cách thả các mục nếu độ dài mới nhỏ hơn, giống như các câu trả lời trước đã được đề xuất.
  • căng/cao cấp danh sách của bạn (trái ngược với tinh giản biên chế) nếu chiều dài mới là lớn hơn, với các tùy chọn bổ sung mà bạn có thể quyết định:
    • tuyến tính suy bw các giá trị được biết đến (tự động chọn nếu danh sách chứa ints hoặc phao)
    • lặp lại mỗi giá trị để họ chiếm một kích thước tương ứng của danh sách mới (tự động chọn nếu danh sách chứa không số)
    • kéo giá trị ban đầu ngoài và để lại những khoảng trống ở giữa

Mọi thứ được thu thập bên trong một chức năng vì vậy nếu bạn cần nó chỉ cần sao chép và dán nó vào tập lệnh của bạn và bạn có thể bắt đầu sử dụng nó ngay lập tức.

Ví dụ bạn có thể nói:

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

và nhận

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

Lưu ý rằng không chính xác nhỏ sẽ xảy ra do hạn chế về dấu chấm động. Ngoài ra, tôi đã viết này cho Python 2.x, do đó, để sử dụng nó trên Python 3.x chỉ cần thêm một dòng duy nhất cho biết xrange = range.

Và đây là một thủ thuật tiện lợi để nội suy giữa các phần con được định vị trong danh sách các danh sách. Vì vậy, ví dụ bạn có thể dễ dàng nội suy giữa các bộ màu RGB để tạo ra một gradient màu sắc của x nr các bước. Giả sử một danh sách các hàng màu RGB của 3 và một biến GRADIENTLENGTH mong muốn bạn làm điều này với:

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

Nó có thể có thể cần một vài tối ưu hóa, tôi đã phải làm khá nhiều thử nghiệm. Nếu bạn cảm thấy bạn có thể cải thiện, hãy chỉnh sửa bài đăng của tôi. Đây là mã:

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