티스토리 뷰
프로젝트에서 통계 자료를 만드는 김에 그 분석도 하면 좋겠다 싶었다.
물론 목적지는 파이썬이지만, 자바로도 비슷한 작업을 할 수 있다는 게 반가워서 가지고 노는 중이다.
Gradle 기준 다음과 같은 의존성을 추가한다.
dependencies {
implementation group: 'tech.tablesaw', name: 'tablesaw-core', version: '0.43.1' // 데이터 분석
implementation group: 'tech.tablesaw', name: 'tablesaw-jsplot', version: '0.43.1' // 데이터 시각화
}
나머지 의존성은 어차피 알아서 하는 거니까 생략했다.
나는 총 두 개의 CSV파일을 이용해서 연습을 진행했다.
하나는 친절하게 한글로 튜토리얼을 써 주신 분과 같은 자료이고,
또 하나는 위도와 경도를 이용해 그래프를 찍어보고 싶어서 가져온 다른 자료이다.
그래들에 의존성을 추가했으면 경로를 이용해 파일을 우선 읽어온다.
한글 이름이 혹시 에러를 일으킬까 봐 파일 이름은 test2, test로 변경했다.
public static void main(String[] args) throws IOException {
String BASE_PATH = new File("").getAbsolutePath();
String FILE_NAME = "test2.csv";
String FILE_PATH = BASE_PATH + "/" + FILE_NAME;
}
이어서 테이블 지정 및 출력
Table tb = Table.read().csv(FILE_PATH);
System.out.println(tb);
test2.csv
시도 | 시군구 | 읍면동 | 자격 | 연령구간 | 수급권자수 |
-----------------------------------------------------------
서울특별시 | 종로구 | 종로구 | 기초생계급여 | 18세미만 | 1 |
서울특별시 | 종로구 | 종로구 | 기초생계급여 | 18~64세 | 9 |
서울특별시 | 종로구 | 종로구 | 기초생계급여 | 65세이상 | 3 |
서울특별시 | 종로구 | 청운효자동 | 기초생계급여 | 18세미만 | 10 |
서울특별시 | 종로구 | 청운효자동 | 기초생계급여 | 18~64세 | 61 |
서울특별시 | 종로구 | 청운효자동 | 기초생계급여 | 65세이상 | 61 |
서울특별시 | 종로구 | 청운효자동 | 기초의료급여 | 18세미만 | 1 |
서울특별시 | 종로구 | 청운효자동 | 기초의료급여 | 18~64세 | 8 |
서울특별시 | 종로구 | 청운효자동 | 기초주거급여 | 18세미만 | 11 |
서울특별시 | 종로구 | 청운효자동 | 기초주거급여 | 18~64세 | 25 |
... | ... | ... | ... | ... | ... |
서울특별시 | 강동구 | 둔촌2동 | 기초생계급여 | 18~64세 | 181 |
서울특별시 | 강동구 | 둔촌2동 | 기초생계급여 | 65세이상 | 159 |
서울특별시 | 강동구 | 둔촌2동 | 기초의료급여 | 18세미만 | 2 |
서울특별시 | 강동구 | 둔촌2동 | 기초의료급여 | 18~64세 | 11 |
서울특별시 | 강동구 | 둔촌2동 | 기초의료급여 | 65세이상 | 6 |
서울특별시 | 강동구 | 둔촌2동 | 기초주거급여 | 18세미만 | 16 |
서울특별시 | 강동구 | 둔촌2동 | 기초주거급여 | 18~64세 | 73 |
서울특별시 | 강동구 | 둔촌2동 | 기초주거급여 | 65세이상 | 50 |
서울특별시 | 강동구 | 둔촌2동 | 기초교육급여 | 18세미만 | 10 |
서울특별시 | 강동구 | 둔촌2동 | 기초교육급여 | 18~64세 | 1 |
데이터가 많으면 열 개씩 앞뒤로만 나온다.
내림차순이나 올림차순으로도 출력할 수 있다.
System.out.println(tb.sortDescendingOn("수급권자수"));
test2.csv
시도 | 시군구 | 읍면동 | 자격 | 연령구간 | 수급권자수 |
------------------------------------------------------------
서울특별시 | 강서구 | 등촌3동 | 기초생계급여 | 18~64세 | 2202 |
서울특별시 | 강서구 | 등촌3동 | 기초생계급여 | 65세이상 | 2128 |
서울특별시 | 노원구 | 중계2,3동 | 기초생계급여 | 18~64세 | 1787 |
서울특별시 | 노원구 | 중계2,3동 | 기초생계급여 | 65세이상 | 1646 |
서울특별시 | 강남구 | 수서동 | 기초생계급여 | 65세이상 | 1403 |
서울특별시 | 강서구 | 가양2동 | 기초생계급여 | 65세이상 | 1316 |
서울특별시 | 강서구 | 가양2동 | 기초생계급여 | 18~64세 | 1277 |
서울특별시 | 강남구 | 수서동 | 기초생계급여 | 18~64세 | 1209 |
서울특별시 | 노원구 | 월계2동 | 기초생계급여 | 18~64세 | 1153 |
서울특별시 | 노원구 | 월계2동 | 기초생계급여 | 65세이상 | 1152 |
... | ... | ... | ... | ... | ... |
서울특별시 | 용산구 | 한강로동 | 기초의료급여 | 18세미만 | 1 |
서울특별시 | 관악구 | 낙성대동 | 기초교육급여 | 65세이상 | 1 |
서울특별시 | 관악구 | 삼성동 | 기초교육급여 | 18~64세 | 1 |
서울특별시 | 서초구 | 반포4동 | 기초의료급여 | 18세미만 | 1 |
서울특별시 | 용산구 | 남영동 | 기초의료급여 | 18세미만 | 1 |
서울특별시 | 관악구 | 대학동 | 기초교육급여 | 18~64세 | 1 |
서울특별시 | 용산구 | 용산구 | 기초의료급여 | 18~64세 | 1 |
서울특별시 | 동작구 | 상도4동 | 기초의료급여 | 18세미만 | 1 |
서울특별시 | 중구 | 황학동 | 기초교육급여 | 18~64세 | 1 |
서울특별시 | 서초구 | 반포3동 | 기초교육급여 | 18세미만 | 1 |
이어서 원하는 만큼 자료를 확인할 수 있는 메서드.
System.out.println(tb.first(20)); // 처음 20 로우만
System.out.println(tb.last(20)); // 마지막 20 로우만
shape메서드를 쓰면 테이블의 총크기를 알 수 있다.
System.out.println(tb.shape()); // 테이블 모양
test2.csv: 4490 rows X 6 cols
컬럼 목록을 알고 싶으면 아래처럼.
System.out.println(tb.columnNames());
[시도, 시군구, 읍면동, 자격, 연령구간, 수급권자수]
각 컬럼들의 데이터 타입도 확인할 수 있다.
System.out.println(tb.structure()); // 컬럼 데이터 타입
Structure of test2.csv
Index | Column Name | Column Type |
-----------------------------------------
0 | 시도 | STRING |
1 | 시군구 | STRING |
2 | 읍면동 | STRING |
3 | 자격 | STRING |
4 | 연령구간 | STRING |
5 | 수급권자수 | INTEGER |
다음으론 본격적으로 통계라고 부를만한 메서드들.
원하는 컬럼에 대한 요약자료를 출력할 수 있다.
System.out.println(tb.column("시군구").summary());
시군구
Measure | Value |
-----------------------
Count | 4490 |
Unique | 25 |
Top | 송파구 |
Top Freq. | 254 |
이어서 컬럼 하나에 대해 원하는 통계자료만 출력하기.
System.out.println(tb.summarize("수급권자수", max, min, mean, median).by("시군구"));
test2.csv summary
시군구 | Max [수급권자수] | Min [수급권자수] | Mean [수급권자수] | Median [수급권자수] |
----------------------------------------------------------------------------------
종로구 | 326 | 1 | 30.66871165644173 | 10 |
중구 | 290 | 1 | 37.85714285714284 | 16 |
용산구 | 633 | 1 | 52.46296296296294 | 17.5 |
성동구 | 358 | 1 | 55.7182320441989 | 22 |
광진구 | 501 | 1 | 80.43125 | 40 |
동대문구 | 724 | 1 | 102.80392156862747 | 39 |
중랑구 | 763 | 1 | 148.14204545454544 | 63.5 |
성북구 | 708 | 1 | 73.74299065420558 | 31.5 |
강북구 | 945 | 1 | 140.08666666666664 | 60 |
도봉구 | 758 | 1 | 94.63225806451614 | 46 |
... | ... | ... | ... | ... |
강서구 | 2202 | 1 | 134.7601809954751 | 52 |
구로구 | 512 | 1 | 72.63068181818186 | 29 |
금천구 | 648 | 1 | 108.95495495495497 | 51 |
영등포구 | 811 | 1 | 57.34196891191711 | 21 |
동작구 | 453 | 1 | 76.04166666666666 | 26.5 |
관악구 | 713 | 1 | 97.54185022026435 | 36 |
서초구 | 628 | 1 | 41.68235294117647 | 14 |
강남구 | 1403 | 1 | 69.18224299065419 | 20 |
송파구 | 467 | 1 | 66.94488188976376 | 22 |
강동구 | 685 | 1 | 81.46391752577318 | 29 |
생각보다 빠르고 예쁘게 표를 뽑아준다.
위 목록에서 max나 min만 출력하는 것도 물론 가능하다.
표에 대한 전체 요약은 아래와 같다.
System.out.println(tb.summary());
test2.csv
Summary | 시도 | 시군구 | 읍면동 | 자격 | 연령구간 | 수급권자수 |
-------------------------------------------------------------------------------------
Count | 4490 | 4490 | 4490 | 4490 | 4490 | 4490 |
Unique | 1 | 25 | 453 | 4 | 3 | |
Top | 서울특별시 | 송파구 | 신사동 | 기초생계급여 | 18세미만 | |
Top Freq. | 4490 | 254 | 21 | 1308 | 1599 | |
sum | | | | | | 384432 |
Mean | | | | | | 85.61959910913147 |
Min | | | | | | 1 |
Max | | | | | | 2202 |
Range | | | | | | 2201 |
Variance | | | | | | 21076.9552852035 |
Std. Dev | | | | | | 145.17904561335118 |
이외에도 필터링 기능이 있지만 그건 나중으로 넘기고,
지금부턴 그래프를 그려보자.
위의 자료에서 몇 개만 뽑아서 그려볼 것이다.
Table table = tb.summarize("수급권자수", mean).by("시군구");
/*
* 막대그래프 (가로)
*/
Plot.show(
HorizontalBarPlot.create(
"시군구 수급권자 수 평균",
table,
"시군구",
"mean [수급권자수]"
)
);
먼저 가로 막대그래프이다.
먼저 정렬을 한 뒤에 그리면 아래와 같이 된다.
Table table = tb.summarize("수급권자수", mean).by("시군구").sortDescendingOn("Mean [수급권자수]");
/*
* 막대그래프 (가로)
*/
Plot.show(
HorizontalBarPlot.create(
"시군구 수급권자 수 평균",
table,
"시군구",
"mean [수급권자수]"
)
);
계속해서 세로그래프를 그려보자.
Table table = tb.summarize("수급권자수", mean).by("시군구").sortDescendingOn("Mean [수급권자수]");
/*
* 막대그래프 (세로)
*/
Plot.show(
VerticalBarPlot.create(
"시군구 수급권자 수 최대값",
table,
"시군구",
"Mean [수급권자수]"
)
);
역시 예상보다 예쁘게 잘 그려준다.
계속해서 원형 그래프를 보자.
Table table = tb.summarize("수급권자수", mean).by("시군구").sortDescendingOn("Mean [수급권자수]");
/*
* 원형 그래프
*/
Plot.show(
PiePlot.create(
"시군구 수급권자 수 평균",
table,
"시군구",
"Mean [수급권자수]"
)
);
이 정도면 기본적인 그래프는 끝난 것 같다.
마지막으로 좌표 데이터를 이용해 점을 찍어보고 끝내자.
파일을 바꿔준다.
String BASE_PATH = new File("").getAbsolutePath();
String FILE_NAME = "test.csv";
String FILE_PATH = BASE_PATH + "/" + FILE_NAME;
Table tb = Table.read().csv(FILE_PATH);
Table table = tb.selectColumns("위도", "경도");
Plot.show(
ScatterPlot.create("노인 장애인 보호구역", table, "경도", "위도")
);
아직 좌표 스케일링 하는 방법을 몰라서 한쪽에 쏠렸지만 제법 한반도 모양이 나온다.
더 많은 데이터로 더 다양한 데이터를 그려보고 싶다. 3차원 그래프라거나 상관 분석이라거나..
시간 나는 대로 데이터를 가지고 놀아봐야겠다.
'Development > Database' 카테고리의 다른 글
[Database]B+Tree, B*Tree (0) | 2023.03.26 |
---|---|
[Database]Index에 대하여 + B-Tree (2) | 2023.03.20 |
[Database]Inner Join, Outer Join, 그리고 (0) | 2023.03.16 |
[ES]Elastic Search, Lucene, 그리고 (2) | 2023.02.15 |
[Redis]레디스(Redis), 스프링부트에 캐싱 적용 (0) | 2023.01.19 |
[Redis]레디스(Redis), StringRedisTemplate 튜토리얼 (2) | 2023.01.18 |
- Total
- Today
- Yesterday
- 백준
- 세모
- 동적계획법
- java
- 지지
- Python
- 스트림
- 맛집
- 알고리즘
- RX100M5
- 유럽
- 면접 준비
- BOJ
- 남미
- Algorithm
- 기술면접
- 스프링
- 세계일주
- spring
- 중남미
- 리스트
- 칼이사
- 여행
- 유럽여행
- a6000
- 세계여행
- Backjoon
- 야경
- 자바
- 파이썬
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |