2012-07-08 1 views
0

위도와 위도가 긴 위치를 한 파일에서 다른 파일의 두 개의 명명 된 필드로 확인하려고합니다.가장 가까운 일치를 사용하는 두 파일의 필드 비교

나는이처럼 하나 개의 파일이 ..

    f1--f2--f3--------f4--------    f5--- 
R    20175155 41273951N078593973W    18012    
R    20175156 41274168N078593975W    18000    
R    20175157 41274387N078593976W    17999    
R    20175158 41274603N078593977W    18024    
R    20175159 41274823N078593978W    18087 

내가 문자를 기반으로 필드를 정의 할 필요가 있도록 각 문자는 특정 위치에있다.

f1 char 18-21; f2 char 22 - 25; f3 char 26-35; f4 char 36-45; f5 char 62-66.

나는 f3, f4, f5에 해당하는 필드 11, 12 및 13이있는 훨씬 더 큰 CSV 파일이 있습니다.

awk -F',' '{print $11, $12, $13}' 
41.46703821 -078.98476926 519.21 
41.46763555 -078.98477791 524.13 
41.46824123 -078.98479015 526.67 
41.46884129 -078.98480615 528.66 
41.46943371 -078.98478482 530.50 

내가 1 개 필드를 파일에 가장 가까운을 찾을 필요가 1 & & 2 파일 2 필드 (11) & & 12;

가장 가까운 당신이 볼 수 있듯이 나는 20

, 파일이 필드 16, 17, 18, 19으로 파일 1 필드 1, 2, 3, 4, 5를 삽입 할 필요가 발견되면 형식이 약간 다릅니다. 이렇게 1 브레이크 다운 파일 ..

파일 1 개

f3-------f4-------- 

DDMMSSdd DDDMMSSdd 

41273951N078593973W 

파일 N은 F3 수단 2

f11-------- f12--------- 

DD dddddddd DDD dddddddd 

41.46703821 -078.98476926 

은 양수이고, W는 F4가 음수 인 것을 의미한다.

I는 잘 작동 SED 말도 한 라이너 1 파일을 변경 .. (나은 방법 ???)

cat $file1 |sed 's/.\{17\}//' |sed 's/\(.\{4\}\)\(.\{4\}\)\(.\{9\}\)\(.\)\(.\{9\}\)\(.\)\(.\{16\}\)\(.\{5\}\)/\1,\2,\3,\4,\5,\6,\8/'|sed 's/\(.\{10\}\)\(.\{3\}\)\(.\{2\}\)\(.\{2\}\)\(.\{2\}\)\(.\{3\}\)\(.\{3\}\)\(.\{2\}\)\(.*\)/\1\2,\3,\4.\5\6\7,\8\9/'|sed 's/\(.\{31\}\)\(.\{2\}\)\(.*\)/\1,\2.\3/' 

2017,5155, 41,27,39.51, N, 078,59을 , 39.73, W, 18,012
2017,5156, 41,27,41.68, N, 078,59,39.75, W, 18000
2017,5157, 41,27,43.87, N, 078,59,39.76, W , 17,999
2017,5158, 41,27,46.03, N, 078,59,39.77, W, 18,024
2017,5159, 41,27,48.23, N, 078,59,39.78, W, 18,087

,

이제 형식을 변환해야합니다. (이 문제는 아래 참조) - 문제 - 숫자가 너무 멀리 반올림됩니다. 나는 적어도 여섯 소수점 이하 자릿수가 필요)

awk -F',' '{for (i=1;i<=NF;i++) {if (i <= 2) printf ($i","); else if (i == 3&&$6 == "S") printf("-"$3+($4/60)+($5/3600)","); else if (i == 3&&$6 == "N") printf($3+($4/60)+($5/3600)","); else if (i == 7&&$10 == "W") printf("-"$7+($8/60)+($9/3600)","); else if (i == 7&&$10 == "E") printf($7+($8/60)+($9/3600)","); if (i == 11) printf ($i"\n")}}' 

2017,5155,41.461, -78.9944,18012
2017,5156,41.4616, -78.9944,18000
2017,5157,41.4622. -
2017,5158,41.4628 78.9944,17999, 난에있어 어디
2017,5159,41.4634 -78.9944,18024, -78.9944,18087

.

해결 본 * 나는 숫자 형식이 공식에서 적어도 6 소수점을 얻을 필요가있다. *

의 printf ($ 3 + ($ 60분의 4) + ($ 3,600분의 5))

의 printf ( 추가 ".8f %" "%. 8 층", $ 3 + ($ 60분의 4) + ($ 5/3600)

다음 호는 필드 파일 1 f3과 f4를 파일 2 f11과 f12에서 가장 일치하는 것과 일치시킵니다.

아이디어가 있으십니까?

그런 다음 입력란 사이의 거리를 계산해야합니다.

는 Excel에서 formuls은 다음과 같이 될 것이다 ..

=ATAN2(COS(lat1)*SIN(lat2)-SIN(lat1)*COS(lat2)*COS(lon2-lon1), SIN(lon2-lon1)*COS(lat2)) 

내가 그 계산을 위해 무엇을 사용할 수 있을까?

* 업데이트 --- 일치하는 위치에 대해 짧은 거리를보고 있습니다. 가장 가까운 성냥에 대한 피타고라스의 정리와 같은 간단한 것을 적용하려고 생각했습니다. 어쩌면 소수점 이하 자릿수도 사용합니다. 몇 배 더 빨라야합니다. 최종 파일이 업데이트 된 후 *

x = (lon2-lon1) * Math.cos((lat1+lat2)/2); 

y = (lat2-lat1); 

d = Math.sqrt(x*x + y*y) * R; 

어쩌면이 같은 ...은 그 때 나는 더 큰 정확성을 위해 필요한 무거운 계산을 할 수 있습니다.

감사

+0

'awk'로 요구되는 정밀도를 얻지 못할 것이라고 생각합니다. 그러나'bc'는 기하학적 함수의 훌륭한 라이브러리 일뿐만 아니라 "임의의 정밀도"를 제공해야합니다. "두 파일 형식을 어떻게 정규화 할 것인가?"와 "파일에 숫자가있을 때 어떻게 bc로 계산합니까?"라는 질문을 나누는 것이 좋습니다. 어쩌면 이미 두 가지 질문을 스스로 해결할 수 있습니다. – tripleee

+0

아마이 게시물은 도움이 될 것입니다 : http://www.linuxjournal.com/magazine/work-shell-calculating-distance-between-two-lituditudelongitude-points – user1498339

+0

@ 삼자 : AWK의'OFMT'와'CONVFMT' 변수를보십시오 .'bc'와 같이 임의의 정밀도를 얻을 수는 없지만,이 애플리케이션을위한 소수점을 충분히 확보 할 수 있습니다. –

답변

0

당신이 가장 일치를 수행 한 후 당신은 거리 계산을 할 수 없습니다가 : 가장 가까운 거리 값의 비교에 의해 정의된다. Awk는 원하는 공식을 평가할 수 있습니다 (큰 원 거리와 비슷합니까?). this chapter을보고 필요한 것을 확인하십시오.

가장 큰 문제는 가장 가까운 일치를 찾는 것입니다. 파일 1의 단일 행을 취하는 awk 스크립트를 작성하고 파일 2의 행을 추가 열로 출력하십시오. 이 열은 거리 수식에 따라 한 쌍의 점 사이의 거리를 계산합니다. 해당 파일을 숫자순으로 정렬하면 (sort -n) 가장 가까운 일치 항목이 맨 위에옵니다. 그런 다음 파일 1의 각 행을 반복하는 스크립트가 필요하며 awk 스크립트를 호출하고 head -n1을 사용하여 가장 가까운 일치 항목을 추출한 다음 원하는 형식으로 출력하십시오.

이것은 모두 bash 및 awk에서 가능하지만 Python에서는 훨씬 간단한 스크립트입니다. 당신이 선호하는 것에 달려 있습니다.