1

Pythonを使用してフライトデータの大きなテスト結果ファイルを解析しましたが、同じ値を出現順にグループ化して行を並べ替える必要があります。

CSVは現在注文されています:

 (Flight ID)                  (Trajectory Data)
20110117559515, , , , , , , , ,2446,6720,370,42  (Time 0)                               
20110117559572, , , , , , , , ,2390,6274,410,54  (Time 0)                               
20110117559574, , , , , , , , ,2391,6284,390,54  (Time 0)                               
20110117559587, , , , , , , , ,2385,6273,390,54  (Time 0)                               
20110117559588, , , , , , , , ,2816,6847,250,32  (Time 0) 
...  

ここでは、すべての一意のIDが、ある時点での現在の軌道データとともに一覧表示されます。この順序は、これらのフライトが空中にある1分ごとに、新しい軌道データで繰り返されます。

再注文が必要な方法は次のとおりです。

20110117559515, , , , , , , , ,2446,6720,370,42  (Time 0)
20110117559515, , , , , , , , ,24xx,67xx,3xx,42  (Time 1)
20110117559515, , , , , , , , ,24xx,67xx,3xx,42  (Time 2)
20110117559515, , , , , , , , ,24xx,67xx,3xx,42  (Time 3)
20110117559515, , , , , , , , ,24xx,67xx,3xx,42  (Time N)
20110117559572, , , , , , , , ,2390,6274,410,54  (Time 0)
20110117559572, , , , , , , , ,23xx,62xx,4xx,54  (Time 1)
20110117559572, , , , , , , , ,23xx,62xx,4xx,54  (Time 2)
... and so on

このジョブを処理するために別のPythonスクリプトを作成しましたが、ファイルサイズが大きいため、3〜4時間かかります。このコンテキストではなじみのないbash/unixツールを使用してこれを行う方法を見つけたいと思います。そして、sortユーティリティのラインに沿って何かを見ていました。

sort -n -s -t, -k1,1 infile.csv > outfile.csv  

-tは区切り文字を設定し、-kは並べ替えキーを設定し、-sは並べ替えを安定させ、-nは数値比較を使用します。

何か案は?(ワンライナーを使用できる場合は、担当者を追加する予定です)。

明確化: 入力データファイルに表示される最初のフライトのすべての詳細を、出力ファイルの先頭でグループ化する必要があります。次に、入力ファイルに表示される2番目のフライト番号のすべての詳細を次にグループ化して、広告を繰り返します。–ジョナサンレフラー

4

3 に答える 3

1

順序を課すためにファイルを前処理し、課された順序を使用してファイルを並べ替えてから、順序情報を削除する必要があると思います。スクリプトのawkスペースが削除されているため、水平スクロールバーなしでSOの1行に収まります。スペースを削除すると、問題が発生します。

awk -F, '{if(order[$1]==0)order[$1]=++counter;print order[$1]","$0;}' infile.csv |
sort -t, -s -k1,1n |
sed 's/^[^,]*,//'

これは、フライト番号(フィールド$1)が以前に表示されたかどうかを確認するために表示されます。そうでない場合は、新しい連番が割り当てられます。次に、行の先頭に連続番号が続き、その後にコンマと元のレコードが続くレコードが出力されます。出力は安定してソートされます(プログラムがそれをサポートしていなくawkても、安定したソートが得られるように変更することが可能です)。sort次に、ソートされた出力の連番が削除されます。私は使用することを選択しましsedたが、cutまたはawkまたは他の多くのプログラムを代わりに使用することができます。

質問のデータに基づいた以下の入力ファイルでテストしましたが、ファイル'587と'588が入力の'572の前に表示されるように並べ替えました(したがって、より酸性のテストです。並べ替え)また、4番目の軌道列の最後の桁をレコードごとに異なる値に設定することで各行を一意にしました(ただし、値は降順であったため、並べ替えがデータで機能している場合は出力されます)注文の)。

20110117559515, , , , , , , , ,2446,6720,370,42
20110117559587, , , , , , , , ,2385,6273,390,54
20110117559588, , , , , , , , ,2816,6847,250,32
20110117559572, , , , , , , , ,2390,6274,410,54
20110117559574, , , , , , , , ,2391,6284,390,54
20110117559515, , , , , , , , ,24xx,67xx,3xx,49
20110117559515, , , , , , , , ,24xx,67xx,3xx,48
20110117559572, , , , , , , , ,2390,6274,410,59
20110117559515, , , , , , , , ,2446,6720,370,47
20110117559515, , , , , , , , ,24xx,67xx,3xx,46
20110117559515, , , , , , , , ,24xx,67xx,3xx,45
20110117559572, , , , , , , , ,23xx,62xx,4xx,58
20110117559572, , , , , , , , ,23xx,62xx,4xx,57

この出力は私には正しいように見えます:

20110117559515, , , , , , , , ,2446,6720,370,42
20110117559515, , , , , , , , ,24xx,67xx,3xx,49
20110117559515, , , , , , , , ,24xx,67xx,3xx,48
20110117559515, , , , , , , , ,2446,6720,370,47
20110117559515, , , , , , , , ,24xx,67xx,3xx,46
20110117559515, , , , , , , , ,24xx,67xx,3xx,45
20110117559587, , , , , , , , ,2385,6273,390,54
20110117559588, , , , , , , , ,2816,6847,250,32
20110117559572, , , , , , , , ,2390,6274,410,54
20110117559572, , , , , , , , ,2390,6274,410,59
20110117559572, , , , , , , , ,23xx,62xx,4xx,58
20110117559572, , , , , , , , ,23xx,62xx,4xx,57
20110117559574, , , , , , , , ,2391,6284,390,54

おそらく、Perlですべてをかなり速く行うことができます。66 MiBは、1つ以上のGiBのRAMを搭載したマシンのメモリに保持するための法外な量のデータではありません。

このPerlスクリプト(genflights.pl)は、約69MiBのデータを作成します。

#!/usr/bin/env perl
use strict;
use warnings;

my $seq = 1000000;

for my $time (0..1500)
{
    for my $flight (0..1000)
    {
        my $r0 = int(rand(1000)) + 20110117559000;
        my $r1 = int(rand(10000));
        my $r2 = int(rand(10000));
        my $r3 = int(rand(1000));
        my $r4 = int(rand(100));
        printf "%s, , ,%07d, ,%04d,%04d,%03d,%02d\n", $r0, ++$seq, $r1, $r2, $r3, $r4;
    }
}

1回の実行からの出力の最初の数行は次のとおりです。

20110117559486, , ,1000001, ,2670,6847,792,91
20110117559489, , ,1000002, ,0278,1929,972,25
20110117559845, , ,1000003, ,9169,4915,145,21
20110117559356, , ,1000004, ,3519,1660,106,97
20110117559976, , ,1000005, ,8988,7830,884,64
20110117559446, , ,1000006, ,7459,7458,791,93
20110117559442, , ,1000007, ,7265,5853,012,41
20110117559686, , ,1000008, ,4624,0682,859,32
20110117559081, , ,1000009, ,3624,0264,017,06
20110117559336, , ,1000010, ,6501,9033,329,33
20110117559869, , ,1000011, ,5020,3008,919,96
20110117559047, , ,1000012, ,5747,4140,693,83
20110117559531, , ,1000013, ,0591,1866,482,68
20110117559355, , ,1000014, ,2254,2731,946,99
20110117559952, , ,1000015, ,0941,0531,743,85

69 MiB(ファイル)を生成するのに約3秒かかりましたflights。次に、上記のスクリプトを(出力をファイルにリダイレクトしてflights.out)「time」で実行し、次の出力を取得しました。

+ awk -F, '{if(order[$1]==0)order[$1]=++counter;print order[$1]","$0;}' flights
+ sort -t, -s -k1,1n
+ sed 's/^[^,]*,//'

real    0m8.658s
user    0m7.881s
sys     0m0.441s

69MiBの処理に10秒未満。

-rw-r--r--  1 jleffler  staff  69115046 Mar 13 09:04 flights
-rw-r--r--  1 jleffler  staff  69115046 Mar 13 09:06 flights.out

出力ファイルが開始されました:

20110117559486, , ,1000001, ,2670,6847,792,91
20110117559486, , ,1001621, ,2274,5287,188,57
20110117559486, , ,1001642, ,2716,6983,778,49
20110117559486, , ,1002791, ,1704,9426,430,05
...
20110117559486, , ,2501369, ,4900,8239,048,70
20110117559486, , ,2501850, ,7114,8721,684,40
20110117559489, , ,1000002, ,0278,1929,972,25
20110117559489, , ,1000090, ,0114,7462,862,55
20110117559489, , ,1000904, ,7780,8559,121,47
20110117559489, , ,1001499, ,9320,8459,592,01
...
20110117559489, , ,2499635, ,5199,8313,668,30
20110117559489, , ,2499955, ,3386,6280,102,19
20110117559489, , ,2500748, ,5740,6370,594,15
20110117559489, , ,2501534, ,1222,9866,714,24
20110117559845, , ,1000003, ,9169,4915,145,21
20110117559845, , ,1000220, ,5341,8347,724,25
20110117559845, , ,1000295, ,5722,4031,045,11
...

これは、2.3 GHz Intel Core i7 MacBook Pro、16 GiB RAM、Mac OSX10.7.5で実行されています。

于 2013-03-13T15:31:23.320 に答える
0

これが私の解決策の試みです。

#!/bin/bash
declare -a ids
declare -A flights
i=0
while IFS= read -r line;
do
   id=$(echo $line | cut -d, -f1)
   if [[ -z ${flights[$id]} ]]; then
       flights[$id]=$line
       ids[$i]=$id
       i=$((i+1))
   else
       flights[$id]=${flights[$id]}$'\n'$line
   fi  
done < infile.csv
for id in "${ids[@]}"
do
    echo "${flights[$id]}"
done > outfile.csv

これは、連想配列を使用しflightsて、各フライトのすべての情報を含む文字列を作成します。idsまた、フライトがファイルに表示される順序を追跡する通常の配列を使用します。

出力するには、配列を繰り返し処理し、ids配列から文字列を出力し続けますflights

これは、いかなる種類のソートも実行しようとはせず、ファイルを1回だけ読み取ります。

于 2013-03-13T15:31:30.137 に答える
0

まったく異なるアプローチ

awk -F',' '{print $0 >> $1;close($1)}' ~/Downloads/newtrajectory.csv

close()それらをすべて開いたままにしておくには多くの人がいるので、ファイルで使用する必要があります。

上記のawk-scriptは、一意のフライトIDと同じ数のファイルを出力します

つまり、ファイル20110117559515にはそのIDのすべてのアイテムが含まれます。

アプローチとほぼ同じ速さsortで、200k行のテストファイルの場合は約5秒です。

後処理ステップとして、catとforループを使用して、すべてを1つのファイルに連結します。

最初の一意のIDを取得するには:

NR>1{
  a[$1]+=1
  if (a[$1] == 2) {
    exit
  }
  else {
    print $1
  }
}

次に、単純なwhileループを使用してすべてを連結できます

 while read line; do cat $line >> final.csv; done < cnt.txt

出力:

$ head final.csv 
20110117559572, , , , , , , , ,2390,6274,410,54
20110117559572, , , , , , , , ,2391,6268,410,101
20110117559572, , , , , , , , ,2392,6261,410,144
20110117559572, , , , , , , , ,2394,6254,410,183
20110117559572, , , , , , , , ,2395,6247,410,219
20110117559572, , , , , , , , ,2397,6240,410,251
20110117559572, , , , , , , , ,2399,6232,410,279
20110117559572, , , , , , , , ,2400,6223,410,304
20110117559572, , , , , , , , ,2402,6215,410,326
20110117559572, , , , , , , , ,2404,6207,410,347

それは私には大丈夫に見えます。

いくつかのタイミング:

$ time awk -F',' '{print $0 >> $1;close($1)}' ~/Downloads/newtrajectory.csv

real    0m14.534s
user    0m4.096s
sys     0m10.101s

$ time awk -F',' -f u.awk ~/Downloads/newtrajectory.csv > cnt.txt

real    0m0.008s
user    0m0.000s
sys     0m0.008s

$ time while read line; do cat $line >> final.csv; done < cnt.txt 

real    0m4.282s
user    0m0.236s
sys     0m1.028s
于 2013-03-13T15:36:47.667 に答える