1. 학습 목표
대용량 데이터 500MB를 읽을 수 있다.
읽어온 데이터를 메모리에 올릴 수 있다.
읽어온 데이터로 데이터 분석을 할 수 있다.
2. 실습 목표
Mdis에서 받은 인구 이동 데이터로 2021 서울에서 가장 많이 이사 간 지역은 어디인지 알아내기
3. 구현
1. 분석할 데이터
1) 분석할 데이터? 2021_인구관련연간자료_20220927_66125.csv
2) 메타 데이터? 데이터들의 정보를 담고 있다. (인덱스, 각 value의 설명 등등)
ex) 인구관련연간자료의 메타 데이터
3) csv란?
•
Comma Separated Values
•
쉼표로 구분된 값 파일이다.
•
파일로 되어있는 데이터를 한줄 씩 읽어서 메모리에 로드해 사용한다. (csv -> java object로)
2. 데이터 처리하는 여러가지 방법
1) Map사용
•
Map에 <"전입,전출",횟수> 이런 식으로 데이터를 처리할 수 있다.
2) Set사용
•
중복을 허용하지 않는 Set을 사용해 지역을 카운트하는 방법으로 처리할 수도 있다.
3) Array사용
•
arr1, arr2를 만들어서 전입 전출을 저장한 다음에 카운트를 할 수도 있다.
•
위의 세가지 방법말고도 다양한 방법들이 있을 수 있다.
3. 코드 작성
0) 주의 사항
•
설계하면서 코드 작성할 것!
1.
논리적 설계 - 기능이 어떤것인지 써보는 것
2.
물리적 설계 - java로 코딩하면 어떤 모양이 될 지 써보는 것
3.
구현 - 설계해둔것으로 코딩
•
메소드 이름 짓기
1.
단일 책임의 원칙 지키기: 메서드는 한 개의 기능만 작동할 수 있도록 작성해야 한다.
2.
어떤 기능을 하는지 알 수 있도록 지어야 한다.(이름이 길어져도 ok, 어차피 컴파일 할 때 빠르게 읽을 수 있도록 알아서 변환한다.)
•
디버깅 하는 법
1.
상단 플레이버튼 오른쪽 디버그 버튼을 눌러서 디버깅 모드로 실행한다.
2.
에러가 나는 부분에 어떤 값이 들어오는지 확인한다.
1) 파일 읽기
PopulationMove 클래스
PopulationStatistics 클래스
•
readByChar() 메소드
◦
FileReader를 사용해서 파일 불러오는 메소드
◦
char c = fileReader.read()가 오류 나는 이유?
▪
read()에 ctrl+좌클릭 해보면 int형으로 반환시키는 것을 알 수 있다.
▪
char로 형변환을 해주면 된다.
◦
fileReader로 작성했을 때 엄청 느릴 줄 알았는데 안 느린 이유?
▪
실행하는 부분만 조금 불러오기 때문이다.(선언을 했을 때 파일을 읽는게 아님)
◦
백만 글자 출력해보기
▪
엄청 느리다(모래를 한알 씩 옮기는 것과 같다.) -> 삽으로 옮기자(BufferedReader 쓰자)
메소드가 점점 많아지면 클래스로 나눠야 한다.
•
파일 별로 클래스나 interface나눠서하기, 한 파일에 interface, class등등 다 넣으면 보긴편하지만 협업을 할 땐 어디에 무슨 클래스가 있는지 찾을 수가 없다.
•
readByLine() 메소드
◦
BufferedReader를 사용해서 파일 불러오는 메소드
◦
readLine을 사용하면 한 줄씩 불러올 수 있다.
◦
데이터가 커서 불러오는데 몇 초걸리긴 하지만 fileReader보다는 빠르다.
•
readByLine2() 메소드
◦
Files.newBufferedReader를 사용해서 파일 불러오는 메소드
◦
요즘 많이 사용하는 스타일이다.
◦
그냥 BufferedReader랑 속도는 비슷하다.
2) parse 구현
parse 메소드
•
parsing이란?
◦
주어진 데이터를 내가 원하는 형태로 가공해서 사용하는 것이다.
•
parse()메소드
◦
전입, 전출 코드를 parsing하는 메소드이다.
◦
split(): String[] 타입으로 리턴하는 메소드, ()안의 구분자로 잘라서 배열에 넣어준다.
ex)
3) readByLine 수정
readByLine 메소드
main 메소드
•
readByLine()메소드 수정
◦
while문 안에서 string을 populationMove로 parsing하여 pml에 add한다.
◦
루프가 끝나면(파일을 모두 읽어서 parsing을 끝냈으면) return한다.
500mb를 매번 읽는 것은 부담이다.
•
왜? 한번 파일을 메모리로 로드 하는데 10초 가량 걸리기 때문이다.
•
따라서 필요한 부분만 파일로 저장해서 사용하면 좋다.(위의 코드에선 전입 전출만 뽑아서 저장)
4) 파일 생성
createAFile 메소드
main 메소드
•
createAFile()메소드
◦
createNewFile를 이용해서 from_to.txt파일을 생성한다
5) 파일 쓰기
write 메소드
fromToString 메소드
main 메소드
•
write()메소드
◦
List를 지정한 파일에 write하는 메소드이다.
◦
write를 이용해 fromToString으로 가공된 데이터를 from_to.txt에 저장한다.
•
fromToString()메소드
◦
전입,전출 코드를 저장할 때 콤마(,)로 구분해서 가공해주는 메소드이다.
6) parse 수정
parse 메소드
main 메소드
•
parse()메소드 수정
◦
전입, 전출 코드만 담겨있는 from_to.txt을 불러와서 사용하기 때문에 인덱스를 0과 1로 바꾼다.
7) count후 저장
getMoveCntMap 메소드
main 메소드
•
getMoveCntMap()메소드
◦
HashMap을 생성해 <“전입,전출”, cnt>의 형식으로 moveCntMap에 저장하는 메소드
1.
List<PopulationMove>를 순환 하면서 "전입,전출" 형태의 key를 만든다.
2.
moveCntMap에서 해당 key에 해당하는 Object가 없으면 생성하고 1이라고 check한다.
3.
key로 꺼내서 +1한다.
4.
moveCntMap을 return한다.
•
getMoveCntMap()메소드에서 return된 moveCntMap을 each_sido_cnt.txt에 저장한다.
8) 히트맵 그리기
heatmapIdxMap 메소드
main 메소드
•
heatmapIdxMap()메소드
◦
각 시도코드를 map에 저장하는 메소드
•
for_heatmap.txt에 [x의 index, y의 index, conut], 형식으로 write한다.
•
결과
4. 추가로 생각해볼 것들
•
객체지향적으로 리펙토링 해보기