여러 파일에서 선택한 열을 하나의 파일로 병합하고 인접한 데이터 행에 대해 일부 계산을 수행하려면 어떻게 해야 합니까?
예를 들면 여러 장치의 여러 데이터 파일이며 각 파일은 매월 여러 센서의 데이터를 보고합니다. 그래서 파일/장치/월이 있고 파일/센서를 원합니다.
다음은 일부 샘플 데이터와 예상 출력입니다.
샘플 데이터 파일 device0_202105.csv
:
Date;Time;Timestamp;PM2_5;AQI;PM10;CO2
2021/05/01;00:00:49;1619827249;21.0;70;29.0;413
2021/05/01;00:10:49;1619827849;20.0;68;37.0;409
2021/05/01;00:20:49;1619828449;21.0;70;39.0;412
2021/05/03;08:10:39;1620029439;33.0;95;43.0;430
2021/05/03;08:20:39;1620030039;33.0;95;50.0;427
2021/05/03;08:30:39;1620030639;35.0;99;38.0;429
2021/05/03;08:40:39;1620031239;33.0;95;46.0;431
2021/05/03;18:10:39;1620065439;12.0;50;18.0;425
2021/05/03;18:20:39;1620066039;12.0;50;18.0;426
샘플 데이터 파일 device0_202106.csv
:
Date;Time;Timestamp;PM2_5;AQI;PM10;CO2
2021/06/01;08:19:16;1622535556;19.0;66;30.0;426
2021/06/01;08:29:16;1622536156;20.0;68;33.0;454
2021/06/01;08:39:16;1622536756;24.0;76;31.0;456
2021/06/01;20:49:16;1622580556;36.0;102;32.0;447
샘플 데이터 파일 device1_202105.csv
:
Date;Time;Timestamp;PM2_5;AQI;PM10;CO2
2021/05/03;11:14:59;1620040499;19.0;66;20.0;438
2021/05/03;11:15:09;1620040509;19.0;66;20.0;486
2021/05/03;11:15:19;1620040519;18.0;63;18.0;485
사용 가능한 전체 데이터 기간(여기서는 202105 및 202106)에 대해 각 센서 유형(예: CO2)에 대한 파일을 생성하고 싶습니다. data-co2.csv
위 데이터를 사용하면 다음과 같습니다.
Date;Time;Device 0;Device 1
2021/05/03;10:30;429.25;469.667
2021/06/01;10:30;475.333
각 장치의 데이터는 열 형식으로 보고됩니다.각 데이터 포인트는 특정 시간 간격에 대한 평균입니다.. 따라서 한 행은 원본 데이터의 한 시간 간격의 평균을 보고합니다.
처음에는 시간 간격당 2개만 고려했습니다.일하는 날만: 오전 8시부터 13시까지의 시간 간격(10:30으로 표시) 및 오후 13시부터 18시까지의 시간 간격(15:30으로 표시).
장치 및 사이클 파일을 반복하는 awk
스크립트로 시작된 스크립트를 실행할 계획입니다 . bash
이것이 내 스크립트의 시작입니다. 그러나 출력 파일을 작성하는 데 문제가 있습니다(해당 -inplace
옵션을 사용해야 합니까?). 저는 더 간단한 경로를 고려하고 있습니다. 즉, 임시 파일에 쓰고 나중에 출력 파일에 연결하는 것입니다.
#!/bin/bash
touch data-co2.csv
gawk -v device=0 -v sensor=18 -f read-data.awk device0_202105.csv data-co2.csv
#!/bin/gawk -f
BEGIN {
FS = "[;/:]";
OFS = ";";
day = 1 ;
sam = 0 ; nam = 0 ; spm = 0 ; npm = 0 ;
}
FNR==NR {
if ( $1 ~ /20[0-9]{2}/ ) {
if ( $3 != day ) {
if ( nam != 0 ) a[date";10:30"] = sam / nam ;
if ( npm != 0 ) a[date";15:30"] = spm / npm ;
day = $3 ;
sam = 0 ; nam = 0 ; spm = 0 ; npm = 0 ;
}
if ( strftime("%u", $7, 1) < 6) {
if ( $4 >= 8 && $4 <= 12 ) {
sam += $sensor ;
++nam ;
}
else if ( $4 >= 13 && $4 < 18 ) {
spm += $sensor ;
++npm ;
}
}
date = $1"/"$2"/"$3 ;
}
next ;
}
{
if ( device == 0 ) {
for ( i in a ) {
print i, a[i] ;
}
}
else {
i = $1"/"$2"/"$3";10:30" ;
j = $1"/"$2"/"$3";15:30" ;
print $0, a[i] ;
print $0, a[j] ;
}
}
각 장치는 서로 다른 시간에 데이터를 보고하며 장치 오류, 네트워크 문제 등으로 인해 데이터가 손실될 수 있다는 점에 유의하시기 바랍니다.
편집됨댓글을 따르세요.
답변1
#setting ":" as FS allows taking hours as separate field
BEGIN { FS="[:;]" ; OFS="\t"
#this gawk feature helps properly addressing the arrays in the end
PROCINFO["sorted_in"] = "@ind_str_asc"
}
#get device ID from filename on every new file
#get device IDs in array
FNR==1 {devID=FILENAME ; sub(/_.*/,"",devID) ; devs[devID]=devID }
#select time ranges, sum up values in time ranges and count occurences
FNR>1 {
if ($2 >= 8 && $2 <= 12) {
vals[devID,$1,1030]=vals[devID,$1,1030]+$NF
n[devID,$1,1030]++
}
else if ($2 >= 13 && $2 <= 17) {
vals[devID,$1,1530]=vals[devID,$1,1530]+$NF
n[devID,$1,1530]++
}
#get dates in array
dates[$1]=$1
}
END {
#needed for value selection
times[1030]="10:30"
times[1530]="15:30"
#print headers
printf("date\ttime")
for (dev in devs) {printf("\t"dev)}
printf("\n")
#print values
for (date in dates) {
#get day of week from system date command
cmd="date -d"date" +%w"
cmd | getline dow
#do not use Sat+Sun
if ( dow != 0 && dow != 6 ) {
for (time in times) {
printf(date"\t"times[time])
for (dev in devs) {
if ( !vals[dev,date,time] ) { printf("\tN/A") }
else { printf("\t"vals[dev,date,time]/n[dev,date,time]) }
}
printf("\n")
}
}
}
}
아마도 가장 우아하지는 않지만 작업이 완료됩니다. gawk
장치의 열 헤더가 값과 일치하는지 확인하려면 배열 순회 옵션 양식이 필요합니다.
샘플 입력을 기반으로 1_04, 2_04 및 3_02라는 이름의 샘플 출력 양식 파일을 생성하고 일부 날짜(5월 1일과 2일은 주말이며 선택되지 않음, "해당 사항 없음"을 테스트하기 위해 더 많은 날짜 추가) 및 일부 숫자 축소(확실함을 보장하기 위해) 수량과 장비가 일치합니다).
date time 1 2 3
2021/05/03 10:30 832 N/A 832
2021/05/03 15:30 406 401 406
2021/05/04 10:30 809 809 1009
2021/05/04 15:30 N/A N/A N/A
2021/05/06 10:30 N/A 832 N/A
2021/05/06 15:30 N/A N/A N/A
보시다시피 모든 장치에 대해 값이 제공되지 않는 경우 하루 전체 또는 시간 간격도 표시됩니다. 그러나 해당 날짜는 로그 파일에 있어야 합니다.