티스토리 뷰

728x90
반응형

프로젝트에서 통계 자료를 만드는 김에 그 분석도 하면 좋겠다 싶었다.

 

물론 목적지는 파이썬이지만, 자바로도 비슷한 작업을 할 수 있다는 게 반가워서 가지고 노는 중이다.

 

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파일을 이용해서 연습을 진행했다.

 

하나는 친절하게 한글로 튜토리얼을 써 주신 분과 같은 자료이고,

 

서울특별시 국민기초생활 수급자 동별 현황_20210731_v1.csv
0.27MB

또 하나는 위도와 경도를 이용해 그래프를 찍어보고 싶어서 가져온 다른 자료이다.

 

전국노인장애인보호구역표준데이터.csv
0.51MB

그래들에 의존성을 추가했으면 경로를 이용해 파일을 우선 읽어온다.

 

한글 이름이 혹시 에러를 일으킬까 봐 파일 이름은 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차원 그래프라거나 상관 분석이라거나..

 

시간 나는 대로 데이터를 가지고 놀아봐야겠다.

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
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
글 보관함