2014-02-26 121 views
1

我具有可構成的數據幀如下:如何高效地將值列表連接到區間列表?

df = pd.DataFrame({'value':scipy.stats.norm.rvs(0, 1, size=1000), 
      'start':np.abs(scipy.stats.norm.rvs(0, 20, size=1000))}) 
df['end'] = df['start'] + np.abs(scipy.stats.norm.rvs(5, 5, size=1000)) 
df[:10] 

     start  value  end 
0 9.521781 -0.570097 17.708335 
1 3.929711 -0.927318 15.065047 
2 3.990466 0.756413 4.841934 
3 20.676291 -1.418172 28.284301 
4 13.084246 1.280723 14.121626 
5 29.784740 0.236915 32.791751 
6 21.626625 1.144663 28.739413 
7 18.524309 0.101871 27.271344 
8 21.288152 -0.727120 27.049582 
9 13.556664 0.713141 22.136275 

每一行代表

分配給的間隔的值(開始,結束)現在,我想獲得的最好的一個列表在時間10,13,15,...,70發生的值。 (如果你熟悉SQL,它類似於SQL中的幾何索引。)

下面是我第一次嘗試python和pandas,它需要18.5ms。任何人都可以幫助改善它嗎? (這個過程將被稱爲1M以上的時期有不同的數據幀在我的計劃)

def get_values(data): 
    data.sort_index(by='value', ascending=False, inplace=True) # this takes 0.2ms 
    # can we get rid of it? since we don't really need sort... 
    # all we need is the max value for each interval. 
    # But if we have to keep it for simplicity it is ok. 
    ret = [] 
    #data = data[(data['end'] >= 10) & (data['start'] <= 71)] 
    for t in range(10, 71, 2): 
     interval = data[(data['end'] >= t) & (data['start'] <= t)] 
     if not interval.empty: 
      ret.append(interval['value'].values[0]) 
     else: 
      for i in range(t, 71, 2): 
       ret.append(None) 
      break 
    return ret 
#%prun -l 10 print get_values(df) 
%timeit get_values(df) 

第二屆學嘗試涉及分解成大熊貓numpy的儘可能多的,它需要大約爲0.7ms

def get_values(data): 
    data.sort_index(by='value', ascending=False, inplace=True) 
    ret = [] 
    df_end = data['end'].values 
    df_start = data['start'].values 
    df_value = data['value'].values 
    for t in range(10, 71, 2): 
     values = df_value[(df_end >= t) & (df_start <= t)] 
     if len(values) != 0: 
      ret.append(values[0]) 
     else: 
      for i in range(t, 71, 2): 
       ret.append(None) 
      break 
    return ret 
#%prun -l 10 print get_values(df) 
%timeit get_values(df) 

我們可以進一步改進嗎?我猜下一步是算法級別,上述兩者都只是樸素的邏輯實現。

回答

2

我沒有在你的代碼明白空的過程,這裏是如果忽略你的空進程更快的版本:

import scipy.stats as stats 
import pandas as pd 
import numpy as np 

df = pd.DataFrame({'value':stats.norm.rvs(0, 1, size=1000), 
      'start':np.abs(stats.norm.rvs(0, 20, size=1000))}) 
df['end'] = df['start'] + np.abs(stats.norm.rvs(5, 5, size=1000)) 

def get_value(df, target): 
    value = df["value"].values 
    idx = np.argsort(value)[::-1] 
    start = df["start"].values[idx] 
    end = df["end"].values[idx] 
    value = value[idx] 

    mask = (target[:, None] >= start[None, :]) & (target[:, None] <= end[None, :]) 
    index = np.argmax(mask, axis=1) 
    flags = mask[np.arange(len(target)), index] 
    result = value[index] 
    result[~flags] = np.nan 
    return result 

get_value(df, np.arange(10, 71, 2)) 
+0

很有啓發!儘管我不知道「空過程」這個詞的意思。 – colinfang

相關問題