Дорогие все, у меня естьбольшойфайл данных, скажем,файл.dat, он содержит два столбца
например, file.dat (показывает несколько строк)
0.0000 -23.4334
0.0289 -23.4760
0.0578 -23.5187
0.0867 -23.5616
0.1157 -23.6045
0.1446 -23.6473
0.1735 -23.6900
0.2024 -23.7324
0.2313 -23.7745
0.2602 -23.8162
0.2892 -23.8574
0.3181 -23.8980
0.3470 -23.9379
0.3759 -23.9772
0.4048 -24.0156
0.4337 -24.0532
0.4627 -24.0898
0.4916 -24.1254
note: data file has a blank line at the end of the file
Ожидаемые результаты
Я хочу найти/извлечь максимум и минимум из обоих столбцов, например, столбец-1
max - 0.4916
min - 0.0000
аналогично столбец-2
max - -23.4334
min - -24.1254
Неполное решение (не работает для столбца 2)
Для столбца-1
awk 'BEGIN{min=9}{for(i=1;i<=1;i++){min=(min<$i)?min:$i}print min;exit}' file.dat
0.0000
cat file.dat | awk '{if ($1 > max) max=$1}END{print max}'
0.4916
для столбца-2
awk 'BEGIN{min=9}{for(i=2;i<=2;i++){min=(min<$i)?min:$i}print min;exit}' file.dat
-23.4334
cat file.dat | awk '{if ($2 > max) max=$2}END{print max}'
**no output showing**
Проблема
Пожалуйста, помогите мне найти минимальное и максимальное значение из столбца 2. примечание: файл данных имеет пустую строку в конце файла
решение1
Проблема в вашем коде,
awk 'BEGIN{min=9}{for(i=2;i<=2;i++){min=(min<$i)?min:$i}print min;exit}' file.dat
... это то, что вы сразу exit
после обработки первой строки ввода. Ваш средний блок там должен быть запущен длякаждыйline. Затем в END
блоке вы можете вывести найденные вами значения. Это делается в другом фрагменте кода:
awk '{if ($1 > max) max=$1}END{print max}'
Другая проблема заключается в том, что вы инициализируете min
с помощью магического числа (9 в первом коде, который я процитировал, и 0 во втором фрагменте; переменные, которые явно не инициализируются, имеют значение 0, если вы используете их в вычислениях). Если это магическое число не попадает в диапазон чисел в реальных данных, то вычисленные значения min и/или max будут неверными. Лучше инициализировать и min, и max каким-то значением, найденным в данных.
Следить заобаДля значений min и max вам понадобятся две переменные, и обе из них необходимо проверить по данным в файле для каждой строки, чтобы увидеть, нуждаются ли они в обновлении.
Поскольку awk
поддерживает массивы, было бы естественно использовать массивы для min
и max
, с одним элементом массива на столбец. Это то, что я сделал в коде ниже.
Обобщенно для любого количества столбцов:
NF == 0 {
# Skip any line that does not have data
next
}
!initialized {
# Initialize the max and min for each column from the
# data on the first line of input that has data.
# Then immediately skip to next line.
nf = NF
for (i = 1; i <= nf; ++i)
max[i] = min[i] = $i
initialized = 1
next
}
{
# Loop over the columns to see if the max and/or min
# values need updating.
for (i = 1; i <= nf; ++i) {
if (max[i] < $i) max[i] = $i
if (min[i] > $i) min[i] = $i
}
}
END {
# Output max and min values for each column.
for (i = 1; i <= nf; ++i)
printf("Column %d: min=%s, max=%s\n", i, min[i], max[i])
}
Учитывая этот сценарий и данные в вопросе:
$ awk -f script.awk file
Column 1: min=0.0000, max=0.4916
Column 2: min=-24.1254, max=-23.4334
Условие NF == 0
для первого блока (который выполняется для всех строк) — гарантировать, что мы пропускаем пустые строки. Тест означает «если в этой строке нет нулевых полей (столбцов) данных». Переменная initialized
будет равна нулю с самого начала (логическиЛОЖЬ), но будет установлен на единицу (логическиистинный) как только будет прочитана первая строка, содержащая данные.
Переменная nf
инициализируется NF
(количеством полей) на строке, из которой мы инициализируем значения min
и max
. Это делается для того, чтобы вывод в END
блоке работал, даже если последняя строка имеет нулевые поля.
решение2
На самом деле, вы можете объединить все инструкции в одну awk
программу:
awk 'NR==1{min1=max1=$1;min2=max2=$2}\
NR>1 {if ($1<min1) {min1=$1} else if ($1>max1) {max1=$1};\
if ($2<min2) {min2=$2} else if ($2>max2) {max2=$2}; }\
END{printf("Column1 min: %f\nColumn1 max: %f\nColumn2 min: %f\nColumn2 max:%f\n",min1,max1,min2,max2)}' file.dat
Это позволит инициализировать минимальные и максимальные значения для обоих столбцов с соответствующими значениями первой строки (правило с условием NR==1
), а затем просканировать последующие строки, чтобы увидеть, являются ли значения больше текущего максимума/меньше текущего минимума соответственно (правило с условием NR>1
).
В конце файла (правило с условием END
) выводится результат.
Уведомлениечто это предполагаетнет пустых строк. Если есть, то нужно заменить NR>1
условие наNR>1 && NF>0
. Если могут быть пустые строкиперед первым, использовать
awk '!init && NF>0 {init=1; min1=max1=$1; min2=max2=$2} \
init==1 && NF>0 {if ($1<min1) {min1=$1} else if ($1>max1) {max1=$1};\
if ($2<min2) {min2=$2} else if ($2>max2) {max2=$2}; }\
END{printf("Column1 min: %f\nColumn1 max: %f\nColumn2 min: %f\nColumn2 max:%f\n",min1,max1,min2,max2)}' file.dat
Это будет использовать переменную init
для проверки того, была ли уже найдена непустая строка, и использовать содержимое первой непустой строки для предварительной установки текущего максимума/минимума для обоих столбцов. Только если init
установлено (после этой инициализации), (непустые) строки рассматриваются для ввода этой статистики.
В качестве общего замечания, вам никогда не придется сохранять cat
файл и передавать результат в awk
.
решение3
С использованиемdatamash
и printf
:
for f in 1 2 ; do printf 'Column #%s\nmax - %s\nmin - %s\n\n' $f \
$(datamash -W max $f min $f < file.dat); done
...или без цикла:
printf 'Column #%s\nmax - %s\nmin - %s\n\n' \
$(datamash -W max 1 min 1 max 2 min 2 < file.dat |
tr -s '\t' '\n' | paste - - | nl)
Вывод либо:
Column #1
max - 0.4916
min - 0
Column #2
max - -23.4334
min - -24.1254
решение4
Это для столбца 1 (он вычисляет среднее максимальное и минимальное значение)
sort -n -k 1 file |awk '{SUM+=$1 ; if ( NR == 1) MIN=$1} END{print "Average - "SUM/NR, "Min time - "MIN,"Max Time - "$1}'
это для col 2
sort -n -k 2 file |awk '{SUM+=$1 ; if ( NR == 1) MIN=$1} END{print "Average - "SUM/NR, "Min time - "MIN,"Max Time - "$1}'