다중 열 csv 파일의 후처리 처리에는 많은(10000+) 줄이 포함되어 있습니다.
ID(Prot), ID(lig), ID(cluster), dG(rescored), dG(before), POP(before)
9000, lig662, 1, 0.421573, -7.8400, 153
10V2, lig807, 1, 0.42692, -8.0300, 149
3000, lig158, 1, 0.427342, -8.1900, 147
3001, lig158, 1, 0.427342, -8.1900, 147
10V2, lig342, 1, 0.432943, -9.4200, 137
10V1, lig807, 1, 0.434338, -8.0300, 147
4000, lig236, 1, 0.440377, -7.3200, 156
10V1, lig342, 1, 0.441205, -9.4200, 135
4000, lig497, 1, 0.442088, -7.7900, 148
9000, lig28, 1, 0.442239, -7.5200, 152
3001, lig296, 1, 0.444512, -7.8900, 146
10V2, lig166, 1, 0.447681, -7.1500, 157
....
4000, lig612, 1, 0.452904, -7.0200, 158
9000, lig123, 1, 0.461601, -6.8000, 160
10V1, lig166, 1, 0.463963, -7.1500, 152
10V1, lig369, 1, 0.465029, -7.3600, 148
내가 지금까지 한 일
나는 함수 awk
에 통합된 다음 코드를 사용하고 있습니다 bash
. 이 코드는 CSV에서 1%(상위 줄)를 가져와 새 CSV로 저장합니다(따라서 줄 수가 감소됨).
take_top44 () {
# Take the top lines from the initial CSV
awk -v lines="$(wc -l < original.csv)" '
BEGIN{
top=int(lines/100)
}
FNR>(top){exit}
1
' original.csv >> csv_with_top_lines.csv
}
지금 하고 싶은 일
awk
원본 CSV에 더 선택적인 필터를 적용하도록 코드를 수정하려면 어떻게 해야 합니까 ? 예를 들어 4번째 열(in dG(rescored)
) 의 값(부동 소수점 수)을 기반으로 데이터를 필터링하려면 어떻게 해야 할까요 ?
minForth = 0.421573
예를 들어 가장 낮은 값(항상 두 번째 줄에 있음 )을 참조로 사용 하고 $4
선택한 임계값(예: 20% 위 minForth
)보다 작은 값이 있는 CSV의 모든 줄을 인쇄해야 합니다.
$4<=(1+0.2)*min))'
답변1
네 번째 필드가 임계값 아래에 있는 모든 행을 필터링하려는 경우 다음 awk
명령이 작동합니다.
awk -F',' -v margin=0.2 'FNR==2 {min=$4} FNR>1&&($4<=(1+margin)*min)' input.csv
또는 필터링된 출력에도 헤더를 포함하려면 다음을 수행합니다.
awk -F',' -v margin=0.2 'FNR==2 {min=$4} FNR==1||($4<=(1+margin)*min)' input.csv
이렇게 하면 파일 구분 기호가 로 설정되고 ,
(단, 필드를 구분하는 추가 공백이 있으므로 파일은 비표준 CSV라는 점에 유의하세요) margin
값이 있는 변수를 0.2
프로그램으로 가져옵니다 awk
.
프로그램 내에서 라인 2( ) min
에 있는 경우 변수 값을 4번째 열의 값으로 설정합니다. FNR==2
그런 다음 라인 1(헤더 - 원하는 경우)에 있거나 파일의 데이터 부분에 있고 네 번째 필드가 1+margin
최소값의 배보다 작은 경우에만 현재 라인을 인쇄합니다.
답변2
이것은 다소 장황한 스크립트입니다. 단축키를 사용하지 말고 에 정보를 인쇄하지 마십시오 stderr
. sh 부분의 경우 일반적으로 맨 위에 "Globals" 값을 설정하는 옵션을 추가할 수 있으므로 인수 외에 옵션을 사용하여 호출할 수 있습니다. 즉:
my_script --max-factor 0.15 -p 20 --out-file foo.csv *.csv
따라서 이 필터링을 통해 rescored
라인의 비율을 필터링합니다. 장황한 부분은 당연히 삭제할 수 있습니다.
#!/bin/sh
# Globals with defaults set
num_lines=0
max_percent_lines=10
max_factor=0.2
fn_in=""
# Default out. Optionally set to another file.
fn_out=/dev/stdout
# As /dev/null to quiet information
fn_err=/dev/stderr
get_num_lines()
{
num_lines=$(wc -l< "$1")
}
print_filtered()
{
awk \
-v num_lines="$num_lines" \
-v max_percent_lines="$max_percent_lines" \
-v max_factor="$max_factor" \
-v fn_err="$fn_err" \
'
BEGIN {
FS=", "
# Exclude header
max_line = (1 + num_lines / 100 * max_percent_lines)
# Truncate
max_line -= max_line % 1
printf "Lines : %d\n",
num_lines - 1 >>fn_err
printf "Line Max : %d (%d%%)\n",
max_line, max_percent_lines >>fn_err
}
NR == 2 {
max_rescored = ($4 + $4 * max_factor)
printf "Rescored Max: %f\n", max_rescored >>fn_err
}
NR > 1 {
print $0
}
NR >= max_line {
printf "Max Line : %d (Exit)\n", max_line >>fn_err
exit
}
$4 >= max_rescored && NR > 2 {
printf "Max Rescored: %f (Exit)\n", $4 >>fn_err
exit
}
' "$fn_in" >>"$fn_out"
}
# Here one could loop multiple input files
명령줄 옵션
의견의 요청에 따라.
옵션을 얻으려면 다양한 방법이 있습니다. 가장 간단한 것은 위치 인수입니다. 예를 들어:
Usage: script percent margin <files ...>
스크립트에서는 다음과 같이 말합니다.
percent=$1
margin=$2
shift
shift
... loop files ...
좀 더 화려하고 유연해지고 싶다면 다음과 같이 할 수 있습니다.
먼저 help
함수를 작성하세요. 그것은 다음과 같을 수 있습니다. (사용 방법에 대해 basename
논의 $0
할 수 있음):
print_help() {
printf "Usage: %s [OPTIONS] <FILES ...>\n" "$(basename "$0")"
printf "\nSome description\n"
printf "\nOPTIONS\n"
printf " -p --percent-lines V Print percent of file. Default %s\n" "$max_percent_lines"
printf " -r --max-factor V Max rescored increase. Default %s\n" "$max_factor"
printf " -o --out-file V Output file. Default stdout\n"
printf " -q --quiet Silence information\n"
printf " -h --help This help\n"
printf " -- Everything after this is input files\n"
printf "\nEverything after first unrecognized option is treated as a file.\n"
}
일반적으로 print_help >&2
stdout이 아닌 stderr로 인쇄하기 위해 as로 호출합니다.
위의 방법 에서는 help
준표준 방식을 사용합니다. -abc
or 는 사용하지 않지만 --foo=123
각 옵션과 인수는 공백으로 구분해야 합니다.
선택적으로 말장난 의도는 없습니다. 다음과 같은 게시물을 확인하세요.
그런 다음 순진한 오류 검사를 통해 나머지 스크립트에 대한 간단한 방법은 다음과 같습니다.
# While not empty
while ! [ -z "$1" ]; do
case "$1" in
-h|--help)
print_help >&2
exit 1
;;
-p|--percent-lines)
shift
max_percent_lines="$1"
;;
-r|--max-factor)
shift
max_factor="$1"
;;
-o|--out-file)
shift
fn_out="$1"
;;
-q|--quiet)
fn_err="/dev/null"
;;
--)
break
;;
*)
break
;;
esac
# Next argument
shift
done
if ! [ -r "$1" ]; then
printf "Unable to read file: \`%s'\n" "$1" >&2
exit 1
fi
# Print header from first file
head -n 1 "$1" >>"$fn_out"
for fn_in in "$@"; do
printf "Processing '%s'\n" "$fn_in" >>"$fn_err"
if ! [ -r "$1" ]; then
printf "Unable to read file: \`%s'\n" "$1" >&2
exit 1
fi
get_num_lines
print_filtered
done
옵션에 대해 더 많은 유효성 검사를 구현할 수 있습니다. 즉, 숫자 등인지 확인하는 것입니다.