據(jù)可視化性能優(yōu)化)
做了這么多年監(jiān)控系統(tǒng)和時序數(shù)據(jù)可視化相關(guān)的工作我遇到過最多的一個場景就是明明后端存了幾千萬個監(jiān)控指標點前端圖表一加載就卡成PPT后端查詢動不動好幾秒領(lǐng)導(dǎo)還盯著屏幕問“為什么曲線這么糊”。說白了這不是硬件問題是數(shù)據(jù)量太大但有效信息密度沒那么高的問題。這中間真正起作用的往往不是更貴的服務(wù)器而是一個高質(zhì)量的時間序列降維算法。LTTBLargest-Triangle-Three-Buckets最大三角形三桶就是目前工程界公認效果好、實現(xiàn)簡單、用得最廣的一種降采樣算法它在保留曲線趨勢和形狀方面明顯優(yōu)于普通抽稀、平均值采樣這些老辦法。這篇文章我不打算只貼一段代碼而是從算法原理、Python實現(xiàn)、參數(shù)調(diào)優(yōu)、真實項目落地、常見坑位這幾個方面把LTTB徹底講透看完你完全可以自己手寫實現(xiàn)并且知道該在什么時候用它、怎么避坑。1. 時間序列降維為什么我最終選了LTTB在做技術(shù)選型之前先得搞清楚我們要解決的核心問題是什么。時間序列降維本質(zhì)上是在數(shù)據(jù)點數(shù)量和原始信息損失之間找一個平衡點。我們手頭可能有一分鐘的監(jiān)控數(shù)據(jù)一年下來就是幾十萬甚至幾千萬個點但用戶看圖表時屏幕寬度就那么多像素2000個點已經(jīng)能把細節(jié)顯示得很清楚了剩下那些點不僅占用帶寬、拖慢渲染而且肉眼根本分辨不出來。這時候就需要降采樣。1.1 數(shù)據(jù)點太多時到底會發(fā)生什么舉個例子我曾經(jīng)在一個物聯(lián)網(wǎng)項目里采集設(shè)備溫度數(shù)據(jù)每臺設(shè)備5秒上報一次一共500臺設(shè)備一天就是864萬條數(shù)據(jù)。查詢某臺設(shè)備一天的曲線時后端一次性返回幾十萬個點。問題立刻暴露出來數(shù)據(jù)庫聚合查詢耗時超過5秒JSON傳輸體積接近10MB瀏覽器canvas繪圖直接掉幀用戶縮放拖動時能明顯感覺到卡頓。如果直接把這些點交給前端去渲染對設(shè)備和網(wǎng)絡(luò)帶寬都是巨大的浪費。更關(guān)鍵的是這幾十萬個點里絕大部分是“平庸數(shù)據(jù)”——溫度曲線平坦的區(qū)域每秒鐘的變化可能只有0.01度這些點對整體趨勢判斷毫無貢獻但占據(jù)了99%的存儲和帶寬成本。降維要做的就是把這些“冗余點”刪掉只留下那些能刻畫曲線形狀的關(guān)鍵點。時間序列數(shù)據(jù)本身有一個很好的特性它是等間隔采樣的連續(xù)曲線在大部分時間段內(nèi)變化平緩。這意味著我們不需要保留每個點只要在變化劇烈的地方多留點、在變化平緩的地方少留點就能用最小的代價還原曲線的大致形狀。這就是所有降采樣算法的基本出發(fā)點。1.2 主流降維方式對比LTTB贏在哪里在LTTB之前工程上最常見的降采樣方案有這幾種方案核心思路優(yōu)點缺點固定間隔抽稀每隔N個點取一個實現(xiàn)簡單、計算極快容易丟失尖峰平坦區(qū)域點太多平均值聚合每N個點算平均得到一個聚合值簡單、能反映整體水平波峰波谷被抹平振幅信息丟失Min-Max聚合每N個點取最小值和最大值能保留極值曲線看起來毛糙且點數(shù)翻倍LTTB分桶后基于最大三角形面積選點趨勢保留好、視覺效果好實現(xiàn)稍復(fù)雜需理解原理固定間隔抽稀是最容易想到的辦法但破綻也最明顯。假如數(shù)據(jù)有一段每秒都在劇烈振蕩的高頻區(qū)間這個區(qū)間可能只有10個點如果抽稀間隔是30那整個高頻區(qū)間可能一個點都留不下來毛刺直接消失曲線看起來就像被刀切過一樣。平均值聚合則會把尖峰拉低、把尖谷填平對需要觀察突刺的場景是致命傷。LTTB的思路完全不同。它不是無腦等間隔刪點而是先把數(shù)據(jù)分成若干個桶然后在每個桶里挑選一個“最能代表這段曲線形狀”的點。怎么定義“最能代表形狀”用數(shù)學(xué)語言說就是在這個桶里找一個點讓這個點和前后桶的代表點構(gòu)成的三角形面積最大。面積越大說明這個點引起的曲線擺動越大信息量也就越大。我后來看到很多開源監(jiān)控系統(tǒng)比如 Grafana 的某些數(shù)據(jù)源插件、時序數(shù)據(jù)庫的降采樣模塊底層用的都是這種基于三角形面積的策略。它在大多數(shù)場景下都能做到“以不到10%的數(shù)據(jù)量還原90%以上的趨勢信息”這是固定抽稀和平均值聚合完全做不到的。這也是為什么說它在國內(nèi)算領(lǐng)先——不是算法本身有多高深而是它把“用更少的數(shù)據(jù)講故事”這件事做到了極致。2. LTTB算法原理最大三角形“三板斧”LTTB全稱是Largest-Triangle-Three-Buckets直譯過來就是“最大三角形三桶”。你光看名字可能覺得神秘實際上它的核心邏輯特別樸素把數(shù)據(jù)分成三段處理的思路通過三角形面積來評估一個點的重要性。2.1 一句話理解核心思想想象你在拍攝一場足球賽想用三腳架架一臺相機錄下全場跑動軌跡。如果每隔相等時間拍一張照片你可能拍下了大量球員站在原地閑聊的畫面卻漏掉了進球那個瞬間。而LTTB的做法是把比賽分成幾個時間段在每個時間段里只挑“球員位置變化最大”的那個瞬間拍照。這里的“位置變化最大”落到二維坐標系里就是用三角形面積來衡量。具體思路是針對某一個時間段的候選點連接“前一個已被選中的點”和“后一個時間段的平均位置”形成一個三角形。哪個候選點能讓這個三角形面積最大就選它。面積越大說明這個候選點偏離前后兩個基準點構(gòu)成的直線越遠換句話說它是這段曲線中最“凸出”、最有代表性的點。這種選點方式有個天然優(yōu)勢它能自動感知曲線的變化密度。曲線劇烈波動時局部凸出點很多每個桶里選出的點信息量都很大曲線平坦時所有候選點的三角形面積都很小隨便選一個差異也不大。LTTB因此在視覺上呈現(xiàn)出“自適應(yīng)密度”——變化大的地方點多變化小的地方點少完美契合人眼感知。2.2 算法分步拆解LTTB的標準流程可以分為以下幾步確定目標輸出點數(shù)threshold將原始數(shù)據(jù)點分成threshold個桶。每個桶內(nèi)的點數(shù)大約是數(shù)據(jù)總量 / threshold第一個桶和最后一個桶通常單獨處理。第一個桶中直接取第一個數(shù)據(jù)點作為選中點這個點也是輸出序列的起點。對第2到第threshold-1個桶每次執(zhí)行以下操作計算當前桶“后一個桶”的平均點作為三角形的右端點。平均點的橫坐標是該桶所有點橫坐標的平均值縱坐標同理。以上一個已選點作為三角形左端點。遍歷當前桶內(nèi)所有候選點將候選點與左端點、右端點組成三角形計算面積。選出面積最大的候選點作為當前桶的選中點加入輸出序列。最后一個桶直接取最后一個數(shù)據(jù)點作為輸出序列的終點。這里的“后一個桶”你仔細觀察會發(fā)現(xiàn)每次選點時都要略過“當前桶”本身去拿下一桶的平均點做參考。這個操作是LTTB的精髓它不是只看當前桶內(nèi)部哪些點變化大而是把當前桶放進一個更長的上下文中通過前后參考點的連線判斷哪些點會創(chuàng)造出明顯的“折線感”。2.3 面積計算的數(shù)學(xué)邏輯要親手實現(xiàn)LTTB肯定會遇到三角形面積的計算公式。在二維平面中給定三個點(x1, y1)、(x2, y2)、(x3, y3)三角形面積可以用叉積絕對值的一半表示area abs((x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1)) / 2這個公式的幾何意義很直觀向量(x2 - x1, y2 - y1)和(x3 - x1, y3 - y1)構(gòu)成的平行四邊形的面積再除以2就是三角形面積。為什么用面積而不是用點到直線的距離因為距離只能刻畫“偏離程度”而面積還隱含了底邊的尺度信息。想象兩個候選點一個橫坐標離左端點很近另一個橫坐標離左端點很遠。即使它們的垂直偏離程度相同橫向跨度更大的那個點會讓曲線在該區(qū)間覆蓋更多的橫軸長度從視覺重要性來說通常也更高。三角形面積正好把橫向和縱向兩個維度同時納入考量比只看縱向偏差合理得多。在具體實現(xiàn)中還有個很實用的優(yōu)化點由于三角形的底邊是固定的左端點和右端點都是定值計算面積時不需要每次都除以2直接比較叉積的絕對值大小即可。畢竟我們只需要“誰最大”不需要知道精確的面積數(shù)值。這一小步優(yōu)化能在處理百萬級數(shù)據(jù)點時不明顯拖慢速度。2.4 用視覺直觀理解效果為了直觀說明LTTB的效果想象一段包含一個尖峰、一段振蕩、一段平緩波動的合成曲線。使用普通等間隔抽稀后尖峰可能只剩一兩個點振蕩的細節(jié)完全消失使用LTTB降采樣后尖峰處會保留多個點把峰形勾勒出來振蕩段也保留了疏密有致的采樣點平緩段則只留少量關(guān)鍵節(jié)點。這種“視覺等價性”是LTTB最打動我的地方。它不需要你提前知道數(shù)據(jù)里哪些區(qū)域重要而是自動根據(jù)曲線局部幾何特征決定保留密度。對前端可視化場景來說這就是理想的行為模式。3. 手寫一個LTTBPython實現(xiàn)與性能優(yōu)化原理聽得再好落不了地等于零。下面我把完整可運行的Python代碼寫出來從最樸素的版本開始再逐步加入性能優(yōu)化。3.1 基礎(chǔ)版實現(xiàn)先跑通再說這個版本的核心邏輯嚴格遵循算法步驟適合理解原理。import numpy as np def lttb_downsample(x, y, threshold): 基礎(chǔ)版LTTB降采樣 參數(shù): x: 時間戳或x坐標數(shù)組 y: 對應(yīng)的y值數(shù)組 threshold: 希望保留的目標點數(shù)至少為3 返回: 降采樣后的x索引數(shù)組、x數(shù)組、y數(shù)組 n len(x) if threshold n or threshold 3: return np.arange(n), x, y # 計算每個桶的采樣點數(shù) bucket_size (n - 2) / (threshold - 2) sampled_index [0] # 第一個點必選 prev_point (x[0], y[0]) for bucket_idx in range(1, threshold - 1): # 當前桶的左右邊界索引范圍 start int(1 (bucket_idx - 1) * bucket_size) end min(int(1 bucket_idx * bucket_size), n - 1) if start end: start end - 1 # 下一桶平均點作為右端點 next_start int(1 bucket_idx * bucket_size) next_end min(int(1 (bucket_idx 1) * bucket_size), n) if next_start next_end: next_start next_end - 1 avg_x np.mean(x[next_start:next_end]) avg_y np.mean(y[next_start:next_end]) # 在當前桶內(nèi)找面積最大的點 max_area -1 max_idx start for i in range(start, end): area abs( (x[i] - prev_point[0]) * (avg_y - prev_point[1]) - (avg_x - prev_point[0]) * (y[i] - prev_point[1]) ) if area max_area: max_area area max_idx i sampled_index.append(max_idx) prev_point (x[max_idx], y[max_idx]) sampled_index.append(n - 1) # 最后一個點必選 return np.array(sampled_index), x[sampled_index], y[sampled_index]這段代碼的邏輯可以參考第2章的步驟來對照閱讀。有兩個細節(jié)需要特別注意分桶邊界計算里有個“-2”這是為了讓首尾兩個桶與中間桶的分布更均衡避免最后一個桶內(nèi)點數(shù)過少遍歷當前桶的索引是從start到end但Python的切片是左閉右開所以end需要做邊界保護。3.2 向量化優(yōu)化百萬數(shù)據(jù)點也不怕純Python逐點循環(huán)的問題在于當數(shù)據(jù)點數(shù)達到幾十萬上百萬時慢得讓人抓狂。LTTB的選點邏輯里逐桶內(nèi)的“遍歷找最大面積”其實可以用numpy的向量化運算一次性算完避免Python層級的for循環(huán)。def lttb_downsample_fast(x, y, threshold): n len(x) if threshold n or threshold 3: return np.arange(n), x, y bucket_size (n - 2) / (threshold - 2) sampled_index [0] prev_x, prev_y x[0], y[0] for bucket_idx in range(1, threshold - 1): start int(1 (bucket_idx - 1) * bucket_size) end min(int(1 bucket_idx * bucket_size), n - 1) if start end: start end - 1 next_start int(1 bucket_idx * bucket_size) next_end min(int(1 (bucket_idx 1) * bucket_size), n) if next_start next_end: next_start next_end - 1 avg_x np.mean(x[next_start:next_end]) avg_y np.mean(y[next_start:next_end]) # 向量化計算面積 areas np.abs( (x[start:end] - prev_x) * (avg_y - prev_y) - (avg_x - prev_x) * (y[start:end] - prev_y) ) max_idx start int(np.argmax(areas)) sampled_index.append(max_idx) prev_x, prev_y x[max_idx], y[max_idx] sampled_index.append(n - 1) idx np.array(sampled_index) return idx, x[idx], y[idx]向量化版本的核心優(yōu)化就一句話把“遍歷桶內(nèi)所有點計算面積”改成“用numpy數(shù)組運算一次性得到所有面積再取argmax”。這樣中間桶的循環(huán)次數(shù)從數(shù)據(jù)點數(shù)降到了目標點數(shù)通常目標點數(shù)只有幾百到幾千性能自然大幅提升。我在一臺普通筆記本上跑過實測100萬點降到1000點基礎(chǔ)版耗時約1.6秒向量化版本耗時約0.03秒性能提升超過50倍。對實時監(jiān)控這種低延遲場景來說向量化版本是必須的。3.3 處理邊界情況NaN、長度不足、非等間隔數(shù)據(jù)實際數(shù)據(jù)處理中你一定會遇到各種異常輸入。我總結(jié)了幾類高頻問題包含NaN值如果原始序列中存在NaN面積計算會返回NaNargmax的行為也會變得不穩(wěn)定。處理方式是先把NaN所在位置過濾掉或者在預(yù)處理階段用前后值填充。數(shù)據(jù)長度小于threshold這種情況沒什么好降的直接返回原始數(shù)據(jù)即可。代碼里已經(jīng)有if threshold n的判斷。時間戳非等間隔LTTB本身不要求時間戳嚴格等間隔它用的是索引位置關(guān)系。但非等間隔數(shù)據(jù)會導(dǎo)致“橫軸實際距離”失真建議先統(tǒng)一重采樣到等間隔時間序列以保證面積計算的時間意義。桶內(nèi)點數(shù)為0當threshold接近n時某些桶可能出現(xiàn)start end的情況代碼里做了start end - 1的兜底確保每個桶至少有一個候選點。3.4 與第三方庫的集成參考除了自己實現(xiàn)Python生態(tài)里也有現(xiàn)成的高性能庫可以用。tsdownsample是一個專注于時間序列降采樣的庫內(nèi)部實現(xiàn)了LTTB以及多種變種支持numpy和numba加速接口也很簡潔from tsdownsample import LTTBDownsampler import numpy as np x np.arange(100000) y np.sin(x / 100) np.random.randn(100000) * 0.1 # 返回的是降采樣后的索引 sampled_idx LTTBDownsampler().downsample(x, y, n_out1000)這里我想提醒一句自己實現(xiàn)一遍LTTB非常有必要。因為理解原理之后你才能針對自己的數(shù)據(jù)類型改進算法比如把“下一桶的平均點”替換成“下一桶中與上一選中點連線方向變化最大的點”這類變種在特定場景下效果更好。直接調(diào)庫雖然省事但出了問題你往往不知道該怎么調(diào)。4. 實操案例把LTTB用進真實項目光有代碼還不夠真正的價值在于場景落地。我挑兩個我實際做過的項目場景來拆解一個偏可視化一個偏機器學(xué)習(xí)預(yù)處理都很典型。4.1 案例一監(jiān)控指標曲線降采樣背景是一套服務(wù)器監(jiān)控系統(tǒng)需要把CPU使用率、內(nèi)存占用、網(wǎng)絡(luò)流量這些指標存成時間序列并響應(yīng)前端圖表查詢。由于指標采集頻率高、保留時間長前端查詢原本返回5萬個點造成圖表渲染卡頓。我的處理鏈路是后端從時序數(shù)據(jù)庫讀取原始數(shù)據(jù)后先判斷數(shù)據(jù)點數(shù)是否大于前端可渲染的最大點數(shù)通常設(shè)定為2000如果超過就調(diào)用LTTB降到2000點再返回給前端。這樣前端渲染壓力幾乎恒定不會因為查詢時間范圍變大而變卡。實施后發(fā)現(xiàn)效果非常理想。原先一個7天周期的CPU曲線原始點數(shù)為210萬降采樣后只有2000個點但曲線的波峰、波谷、毛刺全部清晰可見肉眼幾乎察覺不到信息損失。更關(guān)鍵的是網(wǎng)絡(luò)傳輸大小從約15MB降到了約20KB前端渲染時間從1.2秒降到了60毫秒以內(nèi)。用戶體感是“圖表秒開”。這里有一個容易踩的坑Threshold并不是越大越好。如果你把目標點數(shù)設(shè)成5000圖表渲染耗時可能是2000點的好幾倍但視覺信息并沒有增加多少。前端像素寬度就那么寬多出來的點只會造成過度繪制。建議根據(jù)實際渲染寬度來確定目標點數(shù)一般取屏幕像素寬的1.5到2倍就足夠了。4.2 案例二LSTM時間序列預(yù)測前的降維預(yù)處理做深度學(xué)習(xí)時間序列預(yù)測時很多人容易忽略數(shù)據(jù)預(yù)處理的細節(jié)直接把原始數(shù)據(jù)喂給LSTM。我遇到過一個問題傳感器采集的振動信號有大量高頻噪聲直接訓(xùn)練LSTM不僅收斂慢而且預(yù)測結(jié)果飄忽不定。后來我在特征提取環(huán)節(jié)加入LTTB降維把每段10萬點的振動信號降到2000點再作為LSTM的輸入序列。這里LTTB起到的并不是簡單的壓縮作用而是一種“感知重要的提取器”——它能保留振動信號中最顯著的變化點同時丟掉大量平坦冗余區(qū)間相當于把信號中最有辨識度的特征提取出來。實驗結(jié)果表明在相同模型結(jié)構(gòu)下使用LTTB預(yù)處理后預(yù)測誤差降低了約18%訓(xùn)練時間縮短了約35%。當然這里有個前提需要注意LTTB降維后得到的時間序列不再等間隔喂給LSTM之前可能需要做等間隔重采樣或根據(jù)時間步長構(gòu)造序列。我的做法是將降采樣后得到的點按原時間戳位置重新映射到一個固定長度的向量中這樣既保留了關(guān)鍵特征又滿足了LSTM對輸入形狀的要求。4.3 評估降維效果的兩個關(guān)鍵指標在把LTTB應(yīng)用到正式項目前我建議你用量化指標來驗證降維效果不要只靠肉眼。我常用的兩個指標是趨勢保留度計算原始序列與降采樣序列之間的皮爾遜相關(guān)系數(shù)越接近1說明趨勢保留得越好。極值點擊中率定義原始序列中排名前1%的極值點計算降采樣后這些極值點附近例如前后2個點范圍內(nèi)是否仍有保留點命中率越高說明極值保留得越好。用這兩個指標做橫向?qū)Ρ萀TTB通常大幅領(lǐng)先固定抽稀和平均值聚合。特別是在極值保留方面固定抽稀的極值點擊中率往往不到40%而LTTB可以達到85%以上。這個數(shù)字差異在實際業(yè)務(wù)中直接決定了你能否從圖表中一眼定位到故障時間點。5. 常見問題與避坑指南我把自己和身邊同事在實際使用LTTB中踩過的坑集中整理一下按出現(xiàn)頻率從高到低排。5.1 threshold到底設(shè)多少合適這是被問得最多的問題。其實答案高度依賴場景場景推薦threshold說明前端圖表渲染寬度約1500px1000~3000留出冗余避免縮放后點太少服務(wù)端API返回取決于帶寬通常500~2000在傳輸體積和視覺質(zhì)量間平衡機器學(xué)習(xí)預(yù)處理按模型輸入長度定如256/512需要配合后續(xù)重采樣高精度分析場景5000以上保留更多細節(jié)但需接受性能開銷我的經(jīng)驗是寧可先設(shè)低一點比如1000如果發(fā)現(xiàn)曲線有可見的信息丟失再慢慢增加。反過來如果一上來就設(shè)很高的threshold性能問題容易被隱藏且后端壓力也會變大出現(xiàn)問題更難排查。5.2 時間戳不均勻時怎么處理LTTB雖然不要求時間戳等間隔但如果你直接處理非等間隔數(shù)據(jù)由于桶的劃分是按照數(shù)組索引平均切的實際對應(yīng)的時間跨度可能嚴重不均。比如某段時間數(shù)據(jù)密集、另一段時間數(shù)據(jù)稀疏桶內(nèi)的點在時間軸上不是均勻分布選出來的代表點就可能在時間上傾斜。我的建議是先做預(yù)處理將所有數(shù)據(jù)重采樣到一個統(tǒng)一的時間網(wǎng)格上再實施LTTB。如果因為業(yè)務(wù)限制不能重采樣至少也要在算法上按時間戳而非索引來劃分桶這對原版的改動較大但對時間敏感的業(yè)務(wù)場景非常重要。5.3 為什么降采樣后首尾點永遠保留這是LTTB刻意設(shè)計的行為第一個點代表曲線的起點最后一個點代表終點必須保留否則整條曲線會丟失邊界位置。理解這一點后你就能推斷出一個特殊情況如果原始數(shù)據(jù)端點屬于噪聲點LTTB會把噪聲保留下來。處理方法是降采樣前先做一輪平滑或去噪再應(yīng)用LTTB。比如用移動平均窗口去掉極端離群點后再降采樣效果會干凈很多。5.4 誤把LTTB當去噪工具這可能是最大的誤區(qū)。LTTB是降采樣不是濾波。如果一個噪聲尖峰本身是“最大面積點”LTTB不僅不會過濾它反而會因為它的高顯著性而優(yōu)先保留它。如果你要的是平滑曲線應(yīng)該先用Savitzky-Golay濾波、移動平均、小波去噪等方法處理再用LTTB降采樣。兩者職責不同不能互相替代。5.5 大數(shù)據(jù)量下的性能瓶頸LTTB的算法復(fù)雜度為O(n)單次處理100萬個點性能尚可但如果數(shù)據(jù)量達到上億級別單機Python實現(xiàn)可能不夠快。這時候有幾個方向可以考慮先做一次粗粒度的平均值聚合把數(shù)據(jù)量從億級降到百萬級再對聚合結(jié)果應(yīng)用LTTB。這種兩級方案能在不太損失視覺效果的情況下大幅提升性能。利用numba對選點循環(huán)做JIT加速通常比純numpy的向量化版本還要快。如果數(shù)據(jù)在數(shù)據(jù)庫里可以考慮在數(shù)據(jù)庫層面做部分聚合減少傳輸?shù)綉?yīng)用層的數(shù)據(jù)量。我實際用的方案是“數(shù)據(jù)庫預(yù)聚合 應(yīng)用層LTTB”組合即數(shù)據(jù)庫先按小時做平均值聚合把細粒度數(shù)據(jù)壓縮到10萬點以內(nèi)然后應(yīng)用層用LTTB降到2000點。整體延遲從秒級降到了百毫秒級效果非常明顯。寫在最后的實操體會LTTB并不是什么神秘的黑科技它最厲害的地方在于把一個非常直覺化的問題——“哪些點在視覺上更重要”——用三角形面積這個樸素的幾何概念給巧妙解決掉了。我實際用了這么多年最大的體會是它不一定在所有場景下都是數(shù)學(xué)上最優(yōu)的降維方法但在工程實踐里它幾乎總是那個“效果不錯、實現(xiàn)簡單、性能可控、調(diào)整方便”的綜合最優(yōu)解。如果你也在做時序數(shù)據(jù)可視化或者正在為時序預(yù)測模型做數(shù)據(jù)預(yù)處理我強烈建議你先把LTTB的原理吃透再結(jié)合自己項目的實際數(shù)據(jù)去調(diào)參數(shù)。等你踩過幾次坑、把threshold和預(yù)處理流程調(diào)順之后你會發(fā)現(xiàn)這套降維方案至少能陪你走很長一段時間不會過時。