기계에서 이름을 읽었는데 때로는 이러한 판독값이 중복되는 경우도 있습니다.
판독값이 없으면 공백으로 두십시오.
Name Instrument Rep R1 R2 R3
N1 I1 1 1 2 3
N2 I1 1 1 3 4
N1 I1 2 2 3 4
N3 I1 2 3 4 5
N1 I2 1 1 2 3
N2 I2 1 1 3 4
N2 I2 2 2 3 4
N3 I2 1 3 4 5
N1 I3 1 1 4
N2 I3 1 2 5
N3 I3 1 6
N3 I3 2 1
먼저, 평균값(이름별, 위치별)을 사용하여 중복 항목을 병합하고 싶습니다. 그런 다음 이 데이터를 전치하고 .
누락된 값을 점( )으로 바꾸고 싶습니다 .
내가 원하는 출력은
Reading Instrument N1 N2 N3
R1 I1 1.5 1 3
R2 I1 2.5 3 4
R3 I1 3.5 4 5
R1 I2 1 1.5 3
R2 I2 2 3 4
R3 I2 3 4 5
R1 I3 1 2 .
R2 I3 . 5 6
R3 I3 4 . 1
이름과 판독값의 수는 매우 다양합니다. 일부 파일에는 134개 판독값이 있고 다른 파일에는 28개 등이 있지만 판독값은 항상 열 3에서 시작됩니다.
성공하지 못한 채 하나의 열에서만 테스트 실행을 시도한 방법은 다음과 같습니다.
awk '
NR>1{
arr[$1" "$2" "$3] += $4
count[$1" "$2" "$3] += 1
}
END{
for (a in arr) {
print a, arr[a] / count[a]
}
}
' file | awk '
NR == 1 {
n = NF
for (i = 1; i <= NF; i++)
row[i] = $i
next
}
{
if (NF > n)
n = NF
for (i = 1; i <= NF; i++)
row[i] = row[i] " " $i
}
END {
for (i = 1; i <= n; i++)
print row[i]
}'
답변1
간단한 / 를 사용하여 실제로 sed
수행 하려는 경우 awk
실제로 가능합니다.
~처럼언급하다통과조SPACE
, 필드 구분자 로 사용됨&데이터 가치가 문제다 awk
.
그렇기 때문에 sed
먼저 데이터 형식을 다시 지정하는 것이 좋습니다.
sed 's/ *$//'
SPACE
줄 끝에서 s 를 제거합니다 (첫 번째 줄을 제외한 모든 입력 줄은 s 로 끝나 SPACE
므로 입력이 정규화되고 각 줄 끝에서 누락될 수 있는 값이 제거됩니다).
다음으로, 인접한 s의 각 쌍 사이에 a를 삽입합니다 sed 's/ / . /g/'
(행의 끝에 있지 않은 잠재적인 결측값 채우기)..
SPACE
이는 SPACE
인접한 결측값이 있는 경우 추가 s를 삽입하므로 sed 's/ / /g'
이러한 값을 다시 삭제하는 데 사용해야 합니다.
그런 다음 awk
첫 번째 행(예: 헤더)을 사용하여 읽기 이름과 개수를 알고, 각 행 끝에 잠재적인 누락 값을 추가하고(다른 모든 값은 처리됨 sed
) 모든 읽기와 합계를 합산 할 수 있습니다. 해당 이름과 기기를 추적하고 원하는 방향/순서로 평균(있는 경우)을 출력합니다.
sed -e 's/ *$//' -e 's/ / . /g' -e 's/ / /g' <<< 'Name Instrument Rep R1 R2 R3
N1 I1 1 1 2 3
N2 I1 1 1 3 4
N1 I1 2 2 3 4
N3 I1 2 3 4 5
N1 I2 1 1 2 3
N2 I2 1 1 3 4
N2 I2 2 2 3 4
N3 I2 1 3 4 5
N1 I3 1 1 4
N2 I3 1 2 5
N3 I3 1 6
N3 I3 2 1' | awk '
# get number of readings/fields
NR==1{for(i=4;i<=NF;++i)readings[i-4]=$i;fields=NF;next}
# add missing fields in the end
{for(i=NF+1;i<=fields;++i)$i="."}
# keep track of names & instruments
names[$1];instruments[$2]
# sum & count readings per name/instrument (ignoring missing ["."] values)
{for(i=4;i<=NF;++i)if($i!="."){sum[readings[i-4] FS $2 FS $1]+=$i;++count[readings[i-4] FS $2 FS $1]}}
# after reading all data:
END{
# print header
printf "Reading"FS"Instrument";for(name in names)printf FS name;print ""
# sort output rows by instrument
for(instrument in instruments){
# keep order of readings
for(i=0;i<length(readings);++i){
# print first two columns
printf readings[i] FS instrument
# remaining columns (i.e. names):
for(name in names){
# if data available:
if(count[readings[i] FS instrument FS name]){
# print average
printf FS sum[readings[i] FS instrument FS name]/count[readings[i] FS instrument FS name]
# otherwise:
}else{
# print missing value ["."]
printf FS "."
}
# proceed with next row
}print ""
}
}
}
'
참고: 제 생각에는 FS
다차원 배열 인덱싱에서 구분 기호로 사용하는 것이 대부분의 경우 가장 좋은 옵션입니다. 왜냐하면 모든 필드에 이를 포함하지 않는 것이 보장되기 때문입니다(배열을 반복하고 배열의 "차원"을 분할해야 하는 경우). ). 여기서는 필수는 아니지만 습관으로 만들었습니다.
편집하다:조 지적이름/악기가 기록되는 방법이전 버전이 답변에는 추가 설명이 필요할 수 있습니다. 이는 k in a
키가 배열에 존재하는지 확인하는 대신 위에 사용된 단순화된 버전에 영감을 주었습니다.k
a
아니요a[k]
다음 과 같은 항목을 만듭니다 .분배하다이 항목에 대한 NULL 값입니다(그리고 이를 반환합니다).
저에게 있어 위 코드는 귀하가 요청한 출력을 생성합니다.
Reading Instrument N1 N2 N3
R1 I1 1.5 1 3
R2 I1 2.5 3 4
R3 I1 3.5 4 5
R1 I2 1 1.5 3
R2 I2 2 3 4
R3 I2 3 4 5
R1 I3 1 2 .
R2 I3 . 5 6
R3 I3 4 . 1
참고: <<<
제가 사용하는 구문은 HERE-STRING입니다. 이는 모든 셸에서 작동하지 않을 수 있습니다( bash
그러나 지원됩니다). 입력 파일 경로를 전달하면 sed
(내가 아는 한) 모든 쉘에서 작동합니다.
참고: 이는 모든 데이터가 메모리에 맞는 경우에만 작동합니다. 그렇지 않은 경우 입력을 먼저 정렬하여 데이터를 요약하는 메모리 집약도가 낮은 솔루션이 있어야 합니다. 이 경우 행렬을 전치하는 것이 더 까다로울 수 있습니다.
편집하다:
참고: 예제 출력과 달리 내 출력에는 줄 끝에 아무 것도 포함되어 있지 않습니다 SPACE
. 왜냐하면 a를 넣을 때와 넣지 않을 때를 알 수 없기 때문입니다 SPACE
. 이것이 의미가 있다면 질문을 조정해 주시면 이에 따라 답변을 업데이트하겠습니다. 그렇지 않으면 SPACE
예상 출력에서 이러한 을 제거하는 것이 좋습니다.
답변2
현재 문제는 다음과 같습니다.
1) 공백을 필드 구분 기호와 값으로 동시에 사용할 수 없습니다. 값이 고정 길이(값당 하나의 열)인 경우 이를 유리하게 사용할 수 있습니다. 누락된 값을 0으로 설정할 수 있으면 더 쉬울 것입니다. 그러나 이와 같은 경우 누락은 실제로 누락을 의미하므로 해당 항목을 추가 처리에서 제외합니다.
이 방법을 사용하려면 전체 입력 행을 포함하기 위해 $0이 필요합니다. substr($0, offset, 1)을 사용하여 오프셋이 7, 9,11 또는 13인 판독값을 얻을 수 있습니다(인덱스가 0 또는 1에서 시작하는지 잊어버렸습니다. 0이면 각 오프셋에서 빼서 1로 이동합니다).
나머지 논리에 도움이 된다면 빈 누락된 읽기를 M과 같은 자리 표시자로 바꿀 수 있습니다. 그렇지 않으면 여러 공백이 하나의 공백과 동일하며 공백 뒤의 모든 필드는 사실상 더 낮은 필드 번호로 왼쪽으로 이동됩니다.
누락이 0과 같으면 더 쉽습니다. 문제가 있는 공백을 0으로 바꿀 수 있지만 누락된 공백이 0과 다르면 모든 계산이 엉망이 됩니다.
gsub를 사용하여 두 개의 연속 공백과 그 뒤에 세 번째 공백이 있는 모든 항목을 바꾸거나 줄 끝을 "M" 또는 "0"으로 바꿀 수 있습니다.
현재 첫 번째 awk에서는 증분 및 합산 전에 누락 여부를 테스트해야 합니다.
2) 두 번째 awk에서 빈 결측값이 있는 경우 NF도 너무 작을 수 있습니다. 다른 모든 항목은 폐기합니다.
나는 당신의 첫 번째 awk가 무엇을 하는지 이해한다고 생각하지만, 두 번째 awk로 무엇을 성취하고 싶은지 모르겠습니다.
3) 이 출력을 제공하려는 다른 프로그램을 달래기 위해 누락된 값을 나타내기 위해 점을 사용해야 할 수도 있지만 일반적으로 이는 소수점처럼 보이기 때문에 좋지 않은 생각입니다(시스템에서는 합법적입니다). 데이터) 일부 소프트웨어에서는 0 값으로 해석되거나 일반적으로 다른 구문 분석을 더 까다롭게 만들 수 있습니다.