シミュレーションデータ生成の改善

シミュレーションデータ生成の改善

シミュレートされたデータを使用してCSVを生成しようとしています。

for i in {1..1000000..1}
do 
  echo "$i,$(date -d "2017-08-01 + $(shuf -i 1-31 -n 1) days" +'%Y-%m-%d')" >> $F
done;

1から100万まで繰り返し、一意のIDと生成ランダム日付

しかし、非常に遅い実行されます。平行にできる単一の線はありますか?

ベストアンサー1

最後に最終結果を確認してください。

for i in {1..1000000..1}
do 
  echo "$i,$(date -d "2017-08-01 + $(shuf -i 1-31 -n 1) days" +'%Y-%m-%d')" >> $F
done;

シェルループは遅く、この特定のループを特に遅くする2つの主な要因があります。

  1. 繰り返すたびにファイルを開いて追加します。
  2. 外部ユーティリティ(shufand)は各反復で2回実行されます。dateこれはechoおそらくシェルに組み込まれているため、オーバーヘッドが少なくなります。

出力リダイレクトは解決するのが最も簡単です。

for i in {1..1000000..1}
do 
  echo "$i,$(date -d "2017-08-01 + $(shuf -i 1-31 -n 1) days" +'%Y-%m-%d')" 
done >"$F"

これにより、出力ファイルが一度だけ開かれ、ループ中に開いたままになります。


残りのコードはawkGNUを使用してより効率的に実行できますdate(使用しているので、shufLinuxシステムを使用していると仮定するので、date実際にはGNUである可能性が高いですdate)。

awk 'END { for (i=0;i<100;++i) { printf("2017-08-01 + %d days\n", 1+int(31*rand())) }}' /dev/null

これにより、次の100行が生成されます。

2017-08-01 + 22 days
2017-08-01 + 31 days
2017-08-01 + 11 days
2017-08-01 + 27 days
2017-08-01 + 27 days
2017-08-01 + 20 days
(etc.)

これをGNUにインポートしましょうdate。 GNUには、プログラムが出力する日付仕様など、複数の日付仕様をまとめて入力できるdateフラグがあります。-fawk

awk 'END { for (i=0;i<100;++i) { printf("2017-08-01 + %d days\n", 1+int(31*rand())) }}' /dev/null |
date -f - +'%Y-%m-%d'

今私達は得ます

2017-08-23
2017-08-27
2017-08-21
2017-08-29
2017-08-25
2017-08-17
2017-08-07
(etc.)

次に、各行に一意のID(連続した整数)を追加します。

awk 'END { for (i=0;i<100;++i) { printf("2017-08-01 + %d days\n", 1+int(31*rand())) }}' /dev/null |
date -f - +'%Y-%m-%d' |
awk -vOFS=',' '{ print NR, $0 }'

これは君のためだ

1,2017-08-06
2,2017-08-17
3,2017-08-25
4,2017-08-28
5,2017-08-14
6,2017-08-15
7,2017-08-17
8,2017-08-10
9,2017-08-16
10,2017-08-08
(etc.)

これで終わりました。その過程で、私はシェルループがあるという事実を完全に忘れていました。不要であることがわかりました。

100必要な値に設定し、必要に応じて乱数ジェネレータを調整します。rand()0 <= 数値 < 1 になる浮動小数点値を返します。


明らかに、8月(31日の月)にランダムな日付が必要な場合は、date完全にバイパスできます。

awk 'END { for (i=1;i<=100;++i) { printf("%d,2017-08-%02d\n", i, 1+int(31*rand())) }}' /dev/null

BSDではなくGNUawkとMikeのawk()を使用すると、次のように直接正しい日付処理を実行することもできます。mawkawkawk

awk 'END { for (i=1;i<=100;++i) { printf("%d,%s\n", i, strftime("%Y-%m-%d", 1501545600 + int(2678400*rand()),1 )) }}' /dev/null

今、私たちは日付の代わりにUnixタイムスタンプを扱っています。 1501545600は、「2017年8月1日火曜日00:00:00 UTC」に対応し、31日間は2678400秒です。

おすすめ記事