Command-Line

穩健地分割包含雜訊數據的 csv 文件

  • December 4, 2013

假設我有一個包含這些列的 csv 文件:

timestamp,cpu,memory

實際數據形狀的一個範例如下圖:

cpu/mem csv 數據如圖

以這種方式視覺化數據後,人眼很容易分辨出 4 個 CPU 密集型活動的開始和結束位置。

什麼是一種簡單的方法,使用標準的 unix cmd line 工具,理想情況下不訴諸Roroctave等​​,根據“cpu”列**“grep”僅表示這 4 個活動的開始和結束的文件的 8 行**?

顯然這有點模糊,並且數據中有噪音,但是任何給我 8 行接近開始/結束的解決方案都值得讚賞。

csv 文件的簡短摘錄,僅顯示這 4 次活動中的第一次:

10:44:21.310,0,53567488
10:44:22.310,1.56257,53575680
10:44:23.326,0,53854208
10:44:24.325,34.3761,57405440
10:44:25.325,73.43985,61747200
10:44:26.325,3.1251,69459968
10:44:27.325,0,69459968
10:44:28.325,0,69459968
10:44:29.325,65.6271,74756096
10:44:30.325,53.1267,77783040
...
10:50:56.450,35.93865,142700544
10:50:57.450,10.93785,142897152
10:50:58.450,1.56255,142897152
10:50:59.450,0,142897152
10:51:00.450,0,142897152
10:51:01.450,0,142897152

理想情況下,這將導致以下 2 行。

10:44:24.325,34.3761,57405440
10:50:58.450,1.56255,142897152

10:44:26.325但是,由於和之間的幾秒鐘內沒有 cpu 活動10:44:28.325,我不希望答案那麼聰明並且做類似於“平滑”數據的事情。因此,如果像上面這樣的 csv 片段會產生以下 4 行,那就足夠了。

10:44:24.325,34.3761,57405440
10:44:26.325,3.1251,69459968
10:44:29.325,65.6271,74756096
10:50:58.450,1.56255,142897152

一種方法是使用awk. 您可以設置門檻值以獲取達到門檻值的第一行和低於門檻值的最後一行。像這樣的東西可能會起作用:

awk -F, -vthreshold_up=20 -vthreshold_down=10 'BEGIN {
                         cur = "gt";
                       } 
                       {
                         if (cur == "gt" && $2 > threshold_up) {
                           print;
                           cur = "lt";
                         } else if (cur = "lt" && $2 < threshold_down) {
                           print;
                           cur = "gt";
                         }
                       }' file.csv

擴展 jordanm 的方法,我能夠建構出令人驚訝的健壯的東西,而無需求助於統計數據。不幸的是,腳本有點長了,但這已經完成了,現在我可以根據需要經常使用它,只需找出正確的參數。

我在十幾個實際數據文件上對其進行了測試,其中一些和這個一樣混亂:

凌亂的cpu和記憶體csv圖表

這裡的技巧是使用MIN_DURATION變數,它有助於忽略高達指定行數的臨時峰值和下降。

用法:

grep-begin-end FIELD_SEPARATOR FIELD_INDEX THRESHOLD_UP THRESHOLD_DOWN MIN_DURATION ...

例子:

grep-begin-end , 2 30 4 5 file.csv

抓地力開始結束

FIELD_SEPARATOR=$1
FIELD_INDEX=$2
THRESHOLD_UP=$3
THRESHOLD_DOWN=$4
MIN_DURATION=$5
shift 5
awk -F$FIELD_SEPARATOR -vthreshold_up=$THRESHOLD_UP -vthreshold_down=$THRESHOLD_DOWN 'BEGIN {
   cur = "gt";
}
{
   val = $'$FIELD_INDEX';
   # strip of double quotes and convert to number
   if (substr(val, 1, 1) == "\"") { val = 0 + substr(val, 2, length(val) - 3); } else { val = 0 + val; }
   buf = "";
   if (cur == "gt")
   {
       if (val >= threshold_up)
       {
           if (buf == "")
               buf = $0;
           if (duration >= '$MIN_DURATION')
           {
               print buf;
               cur = "lt";
               duration = 0;
               buf = "";
           }
           else
           {
               duration++;
           }
       }
       else
       {
           duration = 0;
       }
   }
   else if (cur == "lt")
   {
       if (val <= threshold_down)
       {
           if (buf == "")
               buf = $0;
           if (duration >= '$MIN_DURATION')
           {
               print buf;
               cur = "gt";
               duration = 0;
               buf = "";
           }
           else
           {
               duration++;
           }
       }
       else
       {
           duration = 0;
       }
   }
}' "$@"

引用自:https://unix.stackexchange.com/questions/101221