株価データなどの CSV データを加工するのに便利なツールとテクニック Windows で動かしています
sed
ストリーミングエディターで行ごとに文字列を加工
sed.exe -e "/^$/d" -e "/^ $/d" -e "s/(\([0-9A-Z]\+\))/,\1.T,/g" -e "s/,//g" -e "s/\t/,/g" -e "s/$/,,,,,,,,,,/g" -e "s/^,*//g" -e "s/$/\r/g"
-e "/^$/d"
: 空行を削除します。-e "/^ $/d"
: スペースだけの行を削除します。-e "s/(\([0-9A-Z]\+\))/,\1.T,/g"
:([0-9A-Z]+)
パターンに一致する部分を,[0-9A-Z].T,
に置き換えます。(\([0-9A-Z]\+\))
: 括弧内に1つ以上の英数字(0-9, A-Z)に一致する部分を見つけます。,\1.T,
: 一致する部分を,[0-9A-Z].T,
に変換します(\1
は一致する部分)。
-e "s/,//g"
: すべてのカンマを削除します。-e "s/\t/,/g"
: タブをカンマに置き換えます。-e "s/$/,,,,,,,,,,/g"
: 各行の末尾に,,,,,,,,,,
を追加します。-e "s/^,*//g"
: 先頭のすべてのカンマを削除します。-e "s/$/\r/g"
: 各行の末尾にキャリッジリターン(改行)を追加します。
sed.exe -n "1p" y:\out.txt
1行目を表示します
sed.exe "s|/\([0-9]\)|/0\1|g; s|/0\([0-9]\{2\}\)|/\1|g"
このスクリプトは、標準の正規表現を使用して日付をフォーマットします。スクリプトの内容を部分ごとに解説します:
最初の部分
s|/\([0-9]\)|/0\1|g
この部分は、日付の月や日の前にゼロを追加します。具体的な正規表現の意味は次の通りです:
s|
は置換コマンドの開始を示します。/
はスラッシュを検索対象に含めるための区切り文字です。\([0-9]\)
は、1桁の数字をキャプチャします。このキャプチャグループは、後で参照されます。|/0\1|
は置換後の文字列です。0\1
は、キャプチャグループ\([0-9]\)
でキャプチャされた1桁の数字の前にゼロを追加します。g
はグローバルオプションで、行全体でこの置換を適用します。
次の部分
s|/0\([0-9]\{2\}\)|/\1|g
この部分は、誤って追加されたゼロを削除します。具体的な正規表現の意味は次の通りです:
s|
は置換コマンドの開始を示します。/0\([0-9]\{2\}\)
は、ゼロに続く2桁の数字をキャプチャします。このキャプチャグループは、後で参照されます。|/\1|
は置換後の文字列です。/\1
はキャプチャグループ\([0-9]\{2\}\)
でキャプチャされた2桁の数字を、そのままスラッシュ後に追加します。g
はグローバルオプションで、行全体でこの置換を適用します。
これで、日付の月や日の前に正しくゼロを追加しつつ、誤って追加されたゼロを削除できます。これにより、日付が 2024/3/1
のような形式から 2024/03/01
のように変換されます。
cut
指定した列を出力します
行末にカンマを複数追加した後このコマンドを使うことによってカンマの数を合わせることができます
cut -d "," -f 1-20,22 y:\output1.txt
paste
2つのファイルを横につなげます
paste.exe y:\t255t255.csv y:\tt252.csv
awk
様々な条件や出力方法の指定が可能
awk -F, '{print $1, $3}' data.csv
縦の CSV を横の CSV に
C:\app\busybox\awk -F "," "NR==1{printf $1 \"",\"" $2; prev=$1; next} {if($1 != prev) {print \""\""; printf $1 \"",\"" $2} else {printf \"",\"" $2}; prev=$1} END{print \""\""}" y:/ticker1.csv > y:/t.csv
カラムの値を比較してカウントし、行の最後にそのカウント結果を追加
C:\app\busybox\awk -F "," "{count=0; for(i=3;i<=NF;i++) if ($i < $(i-1)) count++; print $0 \"",\"" count}" y:/t.csv > y:/t2.csv
trdsql
SQL が使えて便利です
数字の扱いにコツがあります
trdsql -ocrlf -is 1 "select c2 ,replace(c14, ' ', '') ,round(100*(CAST(c2 AS NUMERIC))/(CAST(c3 AS NUMERIC)),1)-100 from y:/t255.csv ORDER BY c13*1 DESC WHERE c2*1 > 100" >y:\ticker.csv
このコマンドは trdsql
を使って、CSVファイル y:/t255.csv
から指定された列を処理し、新しいCSVファイル y:\ticker.csv
に出力するものです。詳細は以下の通りです:
trdsql -ocrlf -is 1
:
-ocrlf
オプションは出力ファイルの行末がCRLF(Windowsスタイル)であることを指定します。-is 1
オプションは、入力ファイルの1行目が列名を含むことを示します。
- SQL クエリ部分:
select c2 ,replace(c14, ' ', '') ,round(100*(CAST(c2 AS NUMERIC))/(CAST(c3 AS NUMERIC)),1)-100 from y:/t255.csv ORDER BY c13*1 DESC WHERE c2*1 > 100
:select c2, replace(c14, ' ', ''), round(100*(CAST(c2 AS NUMERIC))/(CAST(c3 AS NUMERIC)),1)-100
:c2
:第2列のデータを選択します。replace(c14, ' ', '')
:第14列のデータから空白を取り除いたものを選択します。round(100*(CAST(c2 AS NUMERIC))/(CAST(c3 AS NUMERIC)),1)-100
:第2列のデータを数値にキャストしてから、第3列のデータと除算し、その結果を100倍して1桁の精度で四捨五入し、さらに100を引いた値を選択します。from y:/t255.csv
:このクエリはy:/t255.csv
ファイルに対して実行されます。ORDER BY c13*1 DESC
:第13列の数値データを降順で並べ替えます。WHERE c2*1 > 100
:第2列の数値データが100より大きい行のみを対象とします。
- 出力:
>y:\ticker.csv
:クエリの結果をy:\ticker.csv
ファイルに出力します。
trdsql.exe "select c1 ,count(*) from y:/ticker12.csv group by c1" >y:\tick.csv
- SQLクエリ部分:
select c1, count(*) from y:/ticker12.csv group by c1
select c1
: 第1列のデータを選択します。count(*)
: グループごとの行数をカウントします。from y:/ticker12.csv
: このクエリはy:/ticker12.csv
ファイルに対して実行されます。group by c1
: 第1列の値ごとにデータをグループ化します。
- 出力:
>y:\tick.csv
: クエリの結果をy:\tick.csv
ファイルに出力します。
これにより、y:/ticker12.csv
ファイルの第1列に基づいてデータをグループ化し、各グループの行数をカウントした結果が y:\tick.csv
ファイルに保存されます。たとえば、もし y:/ticker12.csv
に第1列が異なる値を持つデータが含まれている場合、その値ごとに行数がカウントされ、新しいCSVファイルに記録されます。
trdsql.exe "SELECT u.*,h.c2 FROM y:\ttt.csv as u LEFT JOIN y:/tick.csv as h ON(u.c1=h.c1) " >y:\tic.csv
- SQLクエリ部分:
SELECT u.*,h.c2 FROM y:\ttt.csv as u LEFT JOIN y:/tick.csv as h ON(u.c1=h.c1)
SELECT u.*, h.c2
:u
テーブル(y:\ttt.csv
の別名)からすべての列を選択し、さらにh
テーブル(y:/tick.csv
の別名)から第2列 (c2
) を選択します。FROM y:\ttt.csv as u
:y:\ttt.csv
ファイルをu
という別名で使用します。LEFT JOIN y:/tick.csv as h ON(u.c1=h.c1)
:y:/tick.csv
ファイルをh
という別名で使用し、u
テーブルのc1
列とh
テーブルのc1
列に基づいて左外部結合を行います。これは、u.c1
とh.c1
の値が一致する行を結合し、一致しない場合でもu
テーブルの全行を保持します。
- 出力:
>y:\tic.csv
: クエリの結果をy:\tic.csv
ファイルに出力します。
これにより、y:\ttt.csv
ファイルと y:/tick.csv
ファイルのデータを結合し、結果を新しいCSVファイルに保存することができます。左外部結合を使用することで、y:\ttt.csv
のすべての行が保持され、対応する y:/tick.csv
のデータが追加されます。
trdsql.exe -is 1 "select c8 ,round(c6, 0),c1 from y:/ticker.csv ORDER BY c8,c1 DESC" >y:\ticker1.csv
- オプション:
-is 1
: 入力ファイルの1行目が列名を含むことを示します。
- SQLクエリ部分:
select c8 ,round(c6, 0),c1 from y:/ticker.csv ORDER BY c8,c1 DESC
select c8, round(c6, 0), c1
:c8
: 第8列のデータを選択します。round(c6, 0)
: 第6列のデータを四捨五入して、整数に変換したものを選択します。c1
: 第1列のデータを選択します。from y:/ticker.csv
: このクエリはy:/ticker.csv
ファイルに対して実行されます。ORDER BY c8, c1 DESC
: 第8列のデータを昇順で、次に第1列のデータを降順で並べ替えます。
- 出力:
>y:\ticker1.csv
: クエリの結果をy:\ticker1.csv
ファイルに出力します。
これにより、y:/ticker.csv
ファイルの第8列、第6列を四捨五入した値、第1列のデータを選択し、指定された順序で並べ替えた結果が y:\ticker1.csv
ファイルに保存されます。
縦に並んでいる株価データを銘柄ごとに横に並べるパッチファイル
setlocal enableDelayedExpansion
set inputFile="y:\ticker1.csv"
set outputFile="y:\t.csv"
:: 初期値を設定
set prevValue=
:: ファイル内の各行を読み込んで処理
(for /f "usebackq tokens=1,2 delims=," %%a in (%inputFile%) do (
set "value1=%%a"
set "value2=%%b"
if "!value1!" neq "!prevValue!" (
if "" neq "!prevValue!" echo ,
SET /P ="!value1!,!value2!" < NUL
) else (
SET /P =",!value2!" < NUL
)
set "prevValue=!value1!"
)) > %outputFile%
echo , >> %outputFile%
このバッチスクリプトは、CSVファイル y:\ticker1.csv
を読み込み、特定の列を処理して新しいCSVファイル y:\t.csv
に保存するものです。詳細な説明を以下に示します:
- 初期設定:
setlocal enableDelayedExpansion
:遅延環境変数展開を有効にします。これはループ内で変数を正しく展開するために必要です。set inputFile="y:\ticker1.csv"
:入力ファイルとしてy:\ticker1.csv
を指定します。set outputFile="y:\t.csv"
:出力ファイルとしてy:\t.csv
を指定します。
- 初期値の設定:
set prevValue=
:前の値を保存する変数prevValue
を初期化します。
- ファイル内の各行を処理:
for /f "usebackq tokens=1,2 delims=," %%a in (%inputFile%) do
:usebackq
:入力ファイルのパスをバッククォートで囲むことを許可します。tokens=1,2
:カンマで区切られた各行の1番目と2番目のフィールドを変数%%a
と%%b
に格納します。delims=,
:フィールド区切り文字をカンマに設定します。
- 行ごとの処理:
set "value1=%%a"
:変数value1
に第1フィールドの値を設定します。set "value2=%%b"
:変数value2
に第2フィールドの値を設定します。if "!value1!" neq "!prevValue!"
:現在の値value1
が前の値prevValue
と異なる場合:if "" neq "!prevValue!" echo ,
:前の値が空でない場合、カンマを出力します。SET /P ="!value1!,!value2!" < NUL
:現在の値value1
とvalue2
を出力ファイルに書き込みます(改行なし)。
else
:現在の値value1
が前の値prevValue
と同じ場合:SET /P =",!value2!" < NUL
:カンマと現在の値value2
を出力ファイルに書き込みます(改行なし)。
set "prevValue=!value1!"
:現在の値value1
をprevValue
に更新します。
- 最後の行処理:
echo , >> %outputFile%
:出力ファイルの最後にカンマを追加します。
株価上昇の回数を数えるバッチファイル
setlocal enabledelayedexpansion
:: 入力ファイルと出力ファイルのパス
set "input_file=y:\tt.csv"
set "output_file=y:\t2.csv"
:: 一時ファイルのパス
set "temp_file=y:\temp.csv"
@echo off
:: 既存の一時ファイルを削除
if exist "%temp_file%" del "%temp_file%"
:: CSVファイルの読み込みと処理
for /F "tokens=*" %%A in (%input_file%) do (
set "line=%%A"
set "count=0"
set /A "i=0"
:: 各列をカウント
for %%B in (!line!) do (
set /A i+=1
if !i! GTR 2 (
if !previous_value! GTR %%B (
set /A count+=1
)
)
set "previous_value=%%B"
)
:: 結果を一時ファイルに出力
echo !line!,!count! >> %temp_file%
)
:: 出力ファイルに一時ファイルの内容をコピー
move /Y %temp_file% %output_file%
具体的なWindows バッチファイルサンプル
最新の13ヶ月分の株価データをZIP ファイルから 解凍して日付を加工した後に出来高が多いものだけ抽出する。縦のデータを横のデータにしてから株価が上昇している回数をカウントします。現在の株価が昔の株価に比べてどれだけの割合で上昇してるかを確認します。その後カウントの多い順に並び替えて名称マスターとマッチングして表示するプログラムです
エクセルなどに取り込んで加工確認してください
5000 | クラ | 566 | 6 | 2 | 11 | 4 | 13 | 28 | 91 | 82 | 84 | 106 | 160 | 206 | 371 | 408 | 402 |
名称マスター
Code,Name
入力データ
Date,Code,Close,Volume
バッチファイル
@echo off
setlocal enabledelayedexpansion
del y:\t1.csv
set count=0
for /f "delims=;" %%f in ('dir /b /o-n C:\data\kabu\*.zip') do (
echo %%f
"C:\app\7-ZipPortable\App\7-Zip64\7z.exe" x -y -o"y:\kabu\" C:\data\kabu\%%f
"C:\app\busybox\sed.exe" "s|/\([0-9]\)|/0\1|g; s|/0\([0-9]\{2\}\)|/\1|g" y:\kabu\%%~nf.csv >y:\kabu\a%%~nf.csv
type y:\kabu\a%%~nf.csv >>y:\t1.csv
set /a count+=1
if !count! geq 13 (
goto :endloop
)
if !count! leq 1 (
"C:\app\Perl\trdsql.exe" "select c2 from y:\kabu\a%%~nf.csv " >y:\n.csv
timeout /t 5
)
)
:endloop
endlocal
echo Loop finished after processing 13 files.
"C:\app\Perl\trdsql.exe" "select c2,c3 ,c4,c1, ROUND(avg(CAST(c4 AS NUMERIC)/1000) OVER(PARTITION BY c2)) from y:/t1.csv ORDER BY c2 DESC ,c1 DESC " >y:\ticker1.csv
"C:\app\Perl\trdsql.exe" "select u.* from y:/ticker1.csv as u JOIN y:/n.csv as h ON(u.c1=h.c1) WHERE u.c5*1>100 " >y:\ticker2.csv
C:\app\busybox\awk -F "," "NR==1{printf $1 \"",\"" $2; prev=$1; next} {if($1 != prev) {print \""\""; printf $1 \"",\"" $2} else {printf \"",\"" $2}; prev=$1} END{print \""\""}" y:/ticker2.csv > y:/ticker0.csv
C:\app\busybox\awk -F "," "NR==1{print $1 \"",\"" $2; prev=$1; next} " y:/ticker1.csv
C:\app\busybox\sed -e "s/$/,,,,,,,,,,,,/g" y:\ticker0.csv>y:\ticker3.csv
C:\app\busybox\cut -d "," -f 1-14 y:\ticker3.csv>y:\ticker4.csv
C:\app\busybox\awk -F "," "{count=0; for(i=3;i<=NF;i++) if ($i*1.0 < $(i-1)) count++; print $0 \"",\"" count}" y:\ticker4.csv > y:\ticker5.csv
C:\app\busybox\awk -F "," "{count=0; for(i=3;i<=5;i++) {if ($i*1.0 < $(i-1)) count++;ww=100;if($i>0) ww=int($2/$i*100+0.5); if (ww< 90) count--; }print $0 \"",\"" count}" y:\ticker5.csv > y:\ticker6.csv
C:\app\busybox\awk -F "," "{printf $1 \"",\"" $2 ; count=0;for(i=3;i<=NF-2;i++){ww=0;if($i>0) ww=int($2/$i*100+0.5)-100;printf \"",\"" ww ; if (ww> 50/(12/(i-2))) count++;} print \"",\"" $(NF-1) \"",\"" $NF \"",\"" count}" y:\ticker6.csv > y:\ticker7.csv
"C:\app\Perl\trdsql.exe" "SELECT u.*,h.c2 FROM y:\ticker7.csv as u LEFT JOIN y:/name.csv as h ON(u.c1=h.c1) ORDER BY u.c15*1 DESC,u.c16*1 DESC,u.c17*1 DESC" >y:\ticker8.csv
C:\app\busybox\sed -e "s/$/,,,,,,,,,,,,/g" y:\ticker8.csv>y:\ticker3.csv
C:\app\busybox\cut -d "," -f 1-24 y:\ticker3.csv >y:\ticker9.csv
trdsql -ocrlf "select c1, c18,c2,c15,c16,c17,c3,c4, c5,c6,c7, c8, c9, c10, c11, c12, c13, c14 from y:\ticker9.csv " >y:\ticker.csv
timeout /t 55&goto:eof
Linux のツールを Windows で使うのはコツが必要です
ディスカッション
コメント一覧
まだ、コメントがありません