심심해서 하는 블로그 :: '분류 전체보기' 카테고리의 글 목록 (9 Page)

1. Buffer Overflow

가장 기본이 되는 예제로 보면 변수 c는 char형 8개를 담을 수 있는 공간이다. 이 곳에 8개 이하의 데이터를 보관하는 것은 문제가 되지 않는다. 근데 9개의 데이터를 넣는 순간 c의 영역을 넘어 다른 공간까지 데이터가 저장되는 것을 알 수 있다. 이처럼 버퍼 오버플로우는 입력의 한계를 충분히 확인하지 않은 API 사용으로 버퍼에 근접한 메모리 주소에 있는 데이터 값을 변경할 때 발생한다. 대표적인 API로는 scanf(), gets(), strcat(), strcpy() 등이 있다. 최근에 나온 컴파일러는 취약한 API에 대하여 사용을 제한하거나 경고하고 있다.


2. 공격 방법(Stack overflow)


메모리에서 스택은 고드름처럼 위에서 성장하는 하며 함수가 호출되면 매게변수 - 리턴 주소 - 지역 순으로 스택에 쌓인다. 반면에 버퍼는 거꾸로 위로 타고 올라가면서 성장한다. 따라서 일정 수준 이상을 입력하게 되면 리턴 주소가 변경된다. 이 특성을 이용하여 공격자는 메모리상에 악성 코드를 주소 A에 두고 리턴 주소를 버퍼 오버플로우를 활용하여 A로 변경하여 원하는 프로그램을 수행시킨다. 이러한 악성코드는 시스템 콜로 구성되어 있다.


3. 예방법

범위를 확인하지 않는 API 사용은 하지 않는다.

대표적인 strcat(), strcpy(), scanf()는 입력의 범위를 확인하지 않고 입력시키는 특징 때문에 버퍼 오버플로우에 취약한 모습을 보여준다. strlcat(), strlcpy(), scanf_s() 등으로 대체하여 사용하는 것이 중요하다.


최신의 운영체제를 사용한다.

운영체제가 발전함에 따라 스택 가드, 스택 쉴드, Non-Executable 스택 등 다양한 방어 장치를 이용해 공격자의 공격을 막는다. 또한 컴파일러도 발전함에 따라 범위 밖의 입력에 대하여는 예외로 처리하여 주며 불완전한 API 사용에 대하여 경고나 금지를 하는 등 최신의 컴파일러를 사용하는 것도 좋은 방법이다. 

,

1. Bus

앞서 CPU와 메모리, I/O 장치 3가지의 요소에 대해 정리해보았다. 이제 이들의 "연결고리" BUS에 대하여 알아보자. 버스는 크게 데이터 버스, 주소 버스, 제어 버스로 나누어진다. 

 

데이터 버스

데이터 버스는 시스템 모듈들 간의 데이터 이동 경로를 제공한다. 주로 32, 64, 128 또는 그 이상의 분리된 선들로 구성되어 있으며 선의 수는 한 번에 전송할수 있는 비트 수를 결정지어 주는데 이것은 CPU가 수용할 수 있는 데이터의 크기, Word와 밀접한 관계가 있다.


주소 버스

주소 버스는 데이터의 근원지나 목적지의 일정한 메모리 주소를 전달하는 버스이다. 

주소 버스의 폭은 최대 기억장치의 용량을 결정지어 주는데 32개의 주소 버스를 지닌 컴퓨터 시스템은 2^32개의 메모리 위치를 할당할 수 있다. 또한 I/O포트를 지정하기 위해서도 사용되어진다.


제어 버스

제어 버스는 데이터 버스와 주소 버스를 제어하기위해 사용되어 진다. 데이터 버스와 주소 버스는 공유하는 선들의 집합이므로 이들을 제어하는 수단이 반드시 필요하기 때문에 사용한다. 


2. 동기식 버스 vs 비동기식 버스

동기식 버스

동기식 버스는 정해진 시간에 데이터를 전송하는 방법이다. 이 때 시간은 버스가 가지고 있는 Clock을 기준으로 하며 빠르고 인터페이스 논리회로가 간단하다는 장점이 있지만 느린 장비도 이 Clock에 맞춰야 한다는 점에서 시간 낭비가 발생할 수 있다. 


비동기식 버스

비동기식 버스는 동기식 버스와 달리 시간을 따로 정하지 않는다. 단지 서로 데이터를 주고 받을 준비가 되어있는지 확인하는 핸드쉐이킹 프로토콜을 사용하여 수신측에서 준비가 되었으면 바로 전송을 하는 방식이다.

장점은 따로 정해진 시간이 없기 때문에 시간 낭비가 적다는 점이고 단점은 회로 구성이 복잡하고 핸드쉐이킹하는 과정이 필요해서 속도도 동기식에 비해 느리다.


3. PCIe

버스의 특징이 공용 선이라는 것인데 이 특징덕분에 한 쪽이 데이터 선을 점령하면 다른 쪽에서는 신호 중첩을 유발 시킬수 있어서 사용을 하면 안된다. 이 점을 보완하기 위해 점대점 상호연결방식이 등장하였다.


QPI(Quick Path Interconnect)

다른 구성요소와 직접연결하는 점대점 상호방식중 하나로 레이어로 구성된 프로토콜 구조이므로 물리적으로 연결되어 있는 부분부터 오류의 존재 여부를 점검하는 등 각각의 레이어에서 하는 일을 구분되어 있다. 고속, 고효율의 패킷 기반의 전송방식을 사용하며 인텔의 i7 데스크톱 프로세서 이후로 사용되어지는 방식이다.


PCIe(Peripheral Component Interconnect Express)

버스를 1대 1로 연결해서 택시로 만들어 버렸다. 높은 용량덕분에 기가이더넷과 같은 빠른 데이터 속도의 I/O 디바이스를 지원하는데 사용되어지며 각각의 버스마다  독립적인 데이터 흐름을 제공하여 많이 사용되어진다. 또한 핀수가 적고 물리적 면적이 작으며 상세한 오류검출 및 보고구조 등의 장점을 가지고 있다.

최근엔 I/O 가상화도 지원한다.


 

,

1. Interrupt

집에서 열심히 라면을 끓이고 있다. (가난한 학생이니까 ㅠㅠ) 라면 물을 끓이고 스프를 넣고 면을 넣고 이제 대망의 계란을 넣을려고 냉장고로 갈려는 순간 갑자기 물이 끓어 넘칠려고 한다. 여러분의 아래의 두 개의 선택지 중에 어떤 것을 선택하겠습니까?


1. 나는 나의 길을 간다. 계란 꺼내고 불을 낮추러 간다.

2. 엄마한테 뒤지게 혼나기 싫다. 불부터 낮춘다. 


대다수의 사람들은 2번을 선택하였을 것이다. 엄마한테 뒤지게 혼나는건 둘째치고 잘못되서 화재라도 나면 살기 위해서 라면 하나 먹다가 인생 하직할순 있으니까..ㅜㅜ 



인터럽트의 개념은 방금 제시한 상황과 비슷하다. CPU가 열심히 프로그램을 수행하는 과정에서

예외나 I/O 장치등 우선순위가 높은 사건이 발생하면 하던 걸 잠시 멈추고 접수받은 내용을 처리하는 과정을 인터럽트라고 한다. 이 때 예외라고 한다면 오버플로우, 0으로 나누기 등등이며 I/O 장치는 하드 디스크, 키보드, 마우스 등등을 의미한다. 컴퓨터 구조 과목에서는 I/O 장치에 대하여 더욱 중점을 둔다.


2. I/O 장치

하드디스크와 같은 I/O 장치들은  프로세서와 직접 데이터를 교환할 수 있고 프로세서는 I/O 모듈에 대하여 쓰기 또는 읽기를 할 수 있다. 프로세서는 I/O들을 구별하기 위해 주소를 사용한다. 

인터럽트가 발생하게 되면 I/O 장비의 상태를 점검하고 준비가 되면 전송하게끔 하는데 인터럽트를 신속 정확하게 처리하고 멈춘 프로그램을 다시 수행해야 하는 CPU에게는 기나긴 시간 낭비이다. 따라서 CPU는 이러한 과정을 I/O 장치에게 시킨다. "그냥 니가 점검해"


I/O 장치가 또 CPU에게 부담을 주는 것은 I/O 장치의 많은 데이터이다.

이 데이터들이 직접 CPU를 거치게 된다면 I/O 인터럽트가 많이 발생해서 CPU는 다른 일은 할 수가 없다.

따라서 CPU의 효율적인 운영을 위해서 DMA(직접 메모리 접근) 기법을 사용한다. 이 방법에서는 I/O장치들이 메인 메모리에 직접 접근하여 입출력을 할 때 CPU에게 시작 인터럽트, 데이터를 Block단위로 쓰고 읽으며 작업이 끝난 후에 CPU에게 종료를 알리는 인터럽트만 보내주면서 CPU의 부담을 확 줄였다.

더나아가 입출력 과정에서 CPU의 부담을 최소로 하면서 병렬적으로 입출력과 연산과정이 동시에 진행할 방법이 필요해지면서 입출력 프로세서(I/O Processor)가 등장하였다. 




,

1. 인덱스(index)

사전에서 APPLE의 뜻을 찾고자 할 때 두 가지의 방법을 사용할 수 있다.

첫번째는 처음부터 하나하나씩 단어를 훑으면서 찾는 방법

두번째는 사전 옆에 붙어있는 A -> P ->.. 순서로 찾는 방법

둘 중에 탐색하는 속도는 두 번쨰의 경우가 더욱 빠르게 탐색이 가능하다.

이처럼 인덱스는 데이터 베이스에서 데이터 탐색 속도를 향상시켜주는 자료 구조이다.

만일 Search Key가 Primary Key를 포함한다면 Primary Index라고 하며, Unique Key를 포함한다면 

Unique Index라고 한다.


2. Clustered vs Unclustered Index



Clustered index와 Unclustered Index의 큰 차이점은 Sorting의 여부이다.

Clustered index는 Date Record가 Key 값을 기반으로 정렬하여 정렬하여 저장한다.

따라서 여러 개가 있으면 데이터 정렬의 순서가 꼬이므로 단 하나만 생성할 수 있다.

또한 정렬이 되어있는 특징 덕분에 전반적으로 불러오기 속도를 엄청나게 향상시키는 효과가 있다.


반면 Unclustered index의 경우 Date Record의 정렬을 하지 않고 저장한다. 

그리고 index 테이블에는 논리적으로 정렬하고 데이터가 있는 페이지 번호와 위치를 표기한다.

따라서 index 테이블은 논리적 정렬을 위해 여러 개가 존재해도 무관하고 덕분에 파일의 크기도 증가한다.


3. Hash-Based Index


해시 인덱스는 검색하고자하는 값을 해시함수에 입력한 후 그 결과와 Bucket의 내용과 비교하여

해당 데이터 레코드의 위치를 찾을 수 있는 인덱스 기법이다. 이 기법의 장점은 Equality 연산에는 좋은 성능을 보인다는 점, 그리고 해시 함수를 특징상 입력 값에 비해 출력 값의 크기는 줄여 Bucket에 저장한다는 점이다. 반면에 단점은 범위를 탐색하는 경우에 매우 비효율적인 성능을 보여준다는 점이다. 


4. B+ Tree Index


B+ Trees는 관계형 데이터 베이스에서 가장 일반적으로 사용되는 인덱스이다.

자료구조때 이진 트리처럼 가운데 키 값과 작거나 같으면 왼쪽 크면 오른쪽으로 트리를 구성한다.

다만 다른 점은 Leaf 노드 간 이동이 가능하다는 점이다. 

Leaf 단계에서 데이터 엔트리들이 포함되어 있기 때문에 B+ Tree의 성능은 트리의 깊이에 의하여 좌우된다.

범위 탐색의 경우에는 Root에서 시작하여 최소 경계값을 찾고 다음 리프 노드로 넘어가는 방식으로 연산을 수행한다. 삽입의 경우에는 필요에 따라 부모 노드가 조정될 수 있다. 마지막 리프 노드가 꽉 차있다면 다시 쪼개서 트리구조를 유지하기 떄문이다.




,

이클립스와 R의 연동은 http://ssoonidev.tistory.com/10 을 참고해주세요


     


1. 준비물 

  1) 카카오톡 대화내용 File

      컴퓨터용 카카오톡 메신저에서 분석하고자하는 대화방에 들어가서 [Ctrl + S]를 누르면 

      대화내용을 Text 파일로 저장할 수 있다. 파일명은 편의상 kakao_temp.txt라고 하였다.


   2) R 스크립트

      주의해야할 것은 아무리 함수가 길더라도 줄바꿈을 하면 안된다. 

      이거 때매 결과가 안 나와서 뻘짓 정말 많이 했다 ㅠㅠ 이름은 form.R로 저장했다.

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
library(KoNLP)
library(wordcloud)
library(RColorBrewer)
library(stringr)
useSejongDic()
 
data1 <- readLines("kakao_temp.txt", encoding = "UTF-8")
data1 <- gsub("손찬호""", data1) # 대화명1
data1 <- gsub("여보♥""",data1)   # 대화명2
data1 <- str_replace_all(data1, "[^[:alpha:]]"""#특수문자 Bye~~ 
data1 <- str_replace_all(data1, "[A-Za-z0-9]""")  #영문, 숫자도 Bye~~
data1 <- gsub("ㅋ""", data1)
data1 <- gsub("ㅠ""", data1)
data1 <- gsub("ㅜ""", data1)
data1 <- gsub("ㅎ""", data1)
data1 <- gsub("오전""", data1)
data1 <- gsub("오후""", data1)
data1 <- gsub("이모티콘""", data1)
data1 <- gsub("월요일""", data1)
data1 <- gsub("화요일""", data1)
data1 <- gsub("수요일""", data1)
data1 <- gsub("목요일""", data1)
data1 <- gsub("금요일""", data1)
data1 <- gsub("토요일""", data1)
data1 <- gsub("일요일""", data1)
data1 <- gsub("년""", data1)
data1 <- gsub("월""", data1)
data1 <- gsub("일""", data1)
data1 <- gsub("음성메세지""", data1)
data1 <- gsub("사진""", data1)
data1 <- gsub("프렌즈팝""", data1)
write(data1,"kakao_1.txt"
 
data2 <- readLines("kakao_1.txt")
data2 <- sapply(data1, extractNoun, USE.NAMES = F)
 
data3 <- unlist(data2)
data3 <- Filter(function(x){nchar(x)>=2 && nchar(x) <= 4}, data3)
 
wordcount <- table(data3)
<- head(sort(wordcount, decreasing = T), 100
write(a,"kakao_count.txt")
 
palete <- brewer.pal(8"Set2")
jpeg(filename = "cloud.jpg", width = 1000, height = 1000)
wordcloud(names(a), freq = a, scale=c(20,2), rot.per = 0.25, min.freq = 1, random.order = F, random.color = T, colors = palete)
dev.off()
cs


   3) 이클립스로 프로젝트를 생성하고 해당 자바 프로젝트 폴더 안에  준비물을 넣어 둔다.

     



2. REnginManager.java

   R 스크립트를 읽어 실행하는 클래스이다. 

   Rengine의 멤버 함수 eval(String text)에서 R스크립트 내용을 수행한다.


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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import java.io.BufferedReader;
import java.io.FileReader;
 
import org.rosuda.JRI.Rengine;
 
public class REngineManager {
    
    /**
     * @class R스크립트 파일을 REngine으로 실행하는 클래스
     */
 
    private Rengine re;
    private boolean isRunning = false;
    private enum SCRIPT_PROCESSING {sucess, fail};
    private SCRIPT_PROCESSING state;
    
    public REngineManager(){
        
    }
 
    public boolean isSucessful(){
        if(state == SCRIPT_PROCESSING.sucess)
            return true;
        else
            return false;
    }
    
    public boolean isRunning(){
        return isRunning;
    }
    
    public void createREngine(){
        String[] Rargs = {"--no-save"};
        re = new Rengine(Rargs, falsenull);
        System.out.println("Create R Engine...");
        
        if(!re.waitForR()){
            System.out.println("Loading R engine was failed");
            isRunning = false;
            return;
        }
        isRunning = true;
        System.out.println("Create R Engine Sucess !!");
        init();
    }
    
    private void init(){
        System.out.println("Install Package....");
        re.eval("install.packages(\"KoNLP\")");
        re.eval("install.packages(\"wordcloud\")");
        re.eval("install.packages(\"RColorBrewer\")");
        re.eval("install.packages(\"httr\")");
        System.out.println("Install Package Complete!!!");
 
    }
    
    public void readScript(String filePath){
        try{
            BufferedReader reader = new BufferedReader(new FileReader(filePath));
            String textLine;
            while(true){
                textLine = reader.readLine();
                if(textLine == null)
                    break;
                re.eval(textLine);
            }
            state = SCRIPT_PROCESSING.sucess;
            reader.close();
        }
        catch(Exception e){
            state = SCRIPT_PROCESSING.fail;
            e.printStackTrace();
        }
    }
    public void close(){
        re.eval("q()");
    }
}
cs

 

3. REnginTest01.java
   이 소스코드는 REngineManager가 잘 운영하는지 보기위해 작성되었다

   form.R의 결과물을 위의 R스크립트에서 cloud.jpg로 저장되어진다.. 

   싱글 쓰레드에서 자바코드와 REngine가 실행되어져서 

   REngine이 실행되어지는 동안에는 자바 코드의 수행이 이루어 지지 않는다. 

   좀 더 효율적인 운영을 위해서 멀티쓰레드 방식을 사용하는 것을 고려해야겠다.


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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import java.awt.BorderLayout;
import java.awt.Color;import java.awt.Component;
import java.awt.Graphics;
import java.awt.Insets;
 
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.Border;
 
import REngine.REngineManager;
 
public class REngineTest01 extends JFrame {
    
    JLabel Image = new JLabel();
    public REngineTest01(){
        init();
    }
    
    private void init(){
        setSize(10001000);
        setLayout(new BorderLayout());
        setLocationRelativeTo(null); // 화면 중앙으로
        setTitle("카카오 워드클라우드");
        setResizable(false);
    }
    
    public void setImg(ImageIcon img){
        Image.setIcon(img);
        add("Center", Image);
        setVisible(true);
    }
    
    public static void main(String[] args){
        
        REngineTest01 testFrame = new REngineTest01();
        
        REngineManager manager = new REngineManager();
        manager.createREngine();
        System.out.println("Read form.R");
        manager.readScript("form.R");
        
        if(manager.isSucessful()){
            System.out.println("Complete");
            System.out.println("Loading Wordcloud Image...");
 
            ImageIcon cloudImg = new ImageIcon("cloud.jpg");
            testFrame.setImg(cloudImg);
 
        }
        else{
            System.out.println("Fail");
        }
 
    }
}
cs



,

역시 삽질은 즐거워... 매번 당하면서도 왜 피하질 못하니ㅠㅠ 


1. R 또는 RStudio를 실행하여 install.packages("rJava")를 실행하여 rJava를 설치한다.

2. [R의 설치 경로]\R-3.3.1\library\rJava\jri로 가면 jar파일 3개가 보인다. 얘네들을 써먹을 거다.




3. 이클립스를 자바 프로젝트를 하나 생성한다.  그 후 해당 프로젝트 오른쪽 마우스 클릭 > Properties 

  Java Build Path > Libraries > Add Extermal JARs.. 클릭 2번의 3개의 파일을 찾아 등록한다. 


4. 환경변수를 추가한다.

    1) R_HOME 추가 : R의 설치경로

       


   2) 환경변수 편집(Window 10.. Window 버전에 따라서 조금 설정화면이 다를 수 있어욤)

       


5. Example Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package Test;
 
import org.rosuda.JRI.REXP;
import org.rosuda.JRI.Rengine;
 
public class REngineTest02 {
    public static void main(String[] args) {
        String[] Rargs = {"--vanilla"};
        Rengine re = new Rengine(Rargs, falsenull);
        System.out.println("Create R Engine...");
        
        if(!re.waitForR()){
            System.out.println("Loading R engine was failed");
            return;
        }
        
        REXP a = re.eval("a <- 10"true);
        System.out.println(a.asDouble());
    }
}
 
cs






,

1. 등장 인물(아니 부품?)

   1) PC (Program Counter) : 다음 실행할 명령어의 주소를 저장

   2) 기억장치 주소 레지스터(MAR) : 다음에 읽거나 쓸 기억장소의 주소를 지정

   3) 기억장치 버퍼 레지스터(MBR) : 기억장치에 저장될 데이터 혹은 기억장치로 부터 읽은 데이터를 임시 저장

   4) 명령어 레지스터(IR) : 현재 수행중인 명령어 저장

   5) 산술 논리 장치(ALU) : 산술연산과 논리연산을 수행 


2. 명령어 패치(Fetch Cycle)

   1) PC에서 다음 수행할 명령어 주소를 MAR에 저장하고 PC에 저장된 주소는 +1


   2) MAR에 저장된 주소에 해당되는 값을 메모리에서 가져와 MBR에 저장

      이 때 메모리에서 받아온 값은 Data 또는 Opcode

  3) Opcode(명령어) 라면  IR에서 명령어를 Decode한다.

   4) 1)~2) 과정으로 Data(Operand)를 메모리로부터 읽어온 후 ALU에서 연산을 수행한다.(Excute Cycle)

       그리고 연산 결과는 MBR을 거쳐 메모리로 다시 저장한다



,

관계대수(Relation Algebra)

컴퓨터 과학의 관계형 데이터베이스의 관계 모델에서, 집합론과 1차 논리에 기반에여 관계로 표현된 데이터를 

취급하는 대수적인 연산체계이다(위키백과 : 관계대수)


2. 추가 연산자 : 기본 연산자들의 조합으로도 만들수 있지만 알고 있으면 편하자나!(내 맘은 불편..)

  1) Join(

    (1) Condition Join(=Theta-join) : Cross-product를 수행한 후 Selection을 한 결과

         

         



    (2) Equi-Join : 조인 대상이 되는 두 테이블에서 공통적으로 존재하는. 컬럼의 일치되는 행을 연결하여 

                              결과를 생성하는 조인 방법 

                              (공통적인 필드는 하나만 표기한다)

    (3) Natural Join : 모든 공통적인 필드에 대한 Equi-Join 


  2) Division( / 

     

    A에 존재하는 <x, y> 튜플에 대하여 B의 모든 튜플 <y>를 포함하는 튜플 <x>의 집합 

 3) Renamimg operator() : 연산 결과를 임시 테이블에 저장하거나 도메인을 변경하기 위한 연산자

     

    A - B 의 결과로 반환된 Relation명을 Temp라 하고 

     Temp의 첫번째 도메인은 userID 세번째 도메인은 result라고 변경한다.

    



,

관계대수(Relation Algebra)

컴퓨터 과학의 관계형 데이터베이스의 관계 모델에서, 집합론과 1차 논리에 기반에여 관계로 표현된 데이터를 

취급하는 대수적인 연산체계이다(위키백과 : 관계대수)


1. 기본 연산자

  1) Selection() : Relation에서 조건에 만족하고 중복 없는[각주:1] 튜플(tuple)들의 Relation을 반환 

     ex)  userTable에서  이름이 ssooni인 사람의 모든 정보를 구하기

           관계대수 > 

           SQL query >  Select * from userTable where name = 'ssooni' 

  

  2) Projection() : Relation에서 원하는 속성(attribute)에 해당하는 중복 없는 튜플(tuple)들로 

                            구성된 Relation을 반환

     ex)  userTable에서 이름이 ssooni인 사람의 전화번호를 구하기

           관계대수 > 

           SQL query > Selete phoneNum from userTable where name='ssooni'


  3) Cross-product() :  두 개의 Relation들을 조합하는 연산자 

      

  4) Set-difference( - ) : 차집합 연산,  연산하고자 하는 Relation들의 각각 대응하는 필드(field)들은 동일한 타입

  5) Union() : 합집합 연산,  연산하고자 하는 Relation들의 각각 대응하는 필드(field)들은 동일한 타입





  1. 집합에서 중복되는 원소는 같은 원소로 취급하기 때문에 중북되는 원소는 제거된다 [본문으로]
,

학교에서 간단하게 배운 R로 일상생활에서 무엇을 해 볼 수 있을까? 고민하다가

"그 동안 여자친구랑 했던 카톡들 중에 어떤 말이 가장 많았을까?" 하는 궁금증에 야심차게(?) 수행해보았다. 


1. 데이터 수집

   컴퓨터 버전 카카오톡에서 [Ctrl + S]를 누르면 이 때까지 상대방과 대화하였던 내용을 .txt파일 형태로 

   저장시켜준다. 그 후 R의 Working Directory 위치에 이 txt파일을 옮겨준다.

   이제 파일을 열어보면....

   허.. 완전 추위에 오돌오돌 떨던 시절의 대화부터 저장되어있다.. txt파일이 12.6MB라니... 

   양이 방대한지라 분석하는데 오래 걸리길래 7월부터 현재까지 대화내용을 분석해 보기로 했다.


2. 데이터 정제

   우선 한글과 워드클라우드로 출력하기 위한 라이브러리를  설치한다.


1
2
3
4
5
6
7
8
9
10
install.packages("KoNLP")
install.packages("wordcloud")
install.packages("RColorBrewer")
install.packages('httr')
library(KoNLP)
library(wordcloud)
library(RColorBrewer)
library(stringr)
 
useSejongDic()
cs


   7월부터 현재까지의 대화내용은 kakao1.txt 파일에 저장되어 있다. 

   특수문자나 숫자, 분석에 필요없는 내용에 대하하여 삭제를 해주는 과정이 필요하다. 

   data1 <- str_replace_all(data1, "[^[:alpha:]]", "") 에서 이 과정을 처리한다.

   카카오톡 계정명인 내 이름과 여자친구 저장명을 삭제하고 

   각 종 게임 아이템 주고 받을 때마다 나오는 메세지 내용을 삭제하고 ㅋㅋ, ㅎㅎ, ㅠㅠ 등등을 

   gsub("대체당할 문자", "대체 하고자하는 문자", 변수)를 활용하여 제거해준다.

   (우리는 프랜즈팝을 즐겨해서 프랜즈팝이 온데간데 등장한다)


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
data1 <- readLines("kakao1.txt")
data1
data1 <- gsub("손찬호""", data1)
data1 <- gsub("여보♥""",data1)
data1 <- str_replace_all(data1, "[^[:alpha:]]""")
data1 <- gsub("부끄럽지만.. 내 (하트)받아주면 안될까?(아잉)""", data1)
data1 <- gsub("어디서 났냐고 다들 물어봐~""", data1)
data1 <- gsub("뭘좋아할지몰""", data1)
data1 <- gsub("단준비한선물""", data1)
data1 <- gsub("님의 핫한 (선물)""", data1)
data1 <- gsub("ㅋ""", data1)
data1 <- gsub("ㅠ""", data1)
data1 <- gsub("ㅜ""", data1)
data1 <- gsub("ㅎ""", data1)
data1 <- gsub("오전""", data1)
data1 <- gsub("오후""", data1)
data1 <- gsub("이모티콘""", data1)
data1 <- gsub("월요일""", data1)
data1 <- gsub("화요일""", data1)
data1 <- gsub("수요일""", data1)
data1 <- gsub("목요일""", data1)
data1 <- gsub("금요일""", data1)
data1 <- gsub("토요일""", data1)
data1 <- gsub("일요일""", data1)
data1 <- gsub("년""", data1)
data1 <- gsub("월""", data1)
data1 <- gsub("일""", data1)
write(data1,"kakao_1.txt") # 정제한 결과 저장
cs

3. 데이터 분석

    어느 정도로 필터링이 완료되면 이제 이것들의 갯수를 새어주는 코드를 작성한다.

    이 때 2글자 이상의 단어만 카운트가 되도록 하였다.

   

1
2
3
4
5
6
data2 <- readLines("kakao_1.txt")
data2 <- sapply(data1, extractNoun, USE.NAMES = F)
data3 <- unlist(data2)
data3 <- Filter(function(x){nchar(x)>=2}, data3)
wordcount <- table(data3)
wordcount
cs

4. 워드클라우드로 표현하기

   이제 집계된 결과를 기반으로 워드클라우드를 만들어 본다.


1
2
3
4
5
<- head(sort(wordcount, decreasing = T), 30)
palete <- brewer.pal(9"Set2")
wordcloud(names(a), freq = wordcount, scale=c(150,0.5), 
        rot.per = 0.25, min.freq = 1, random.order = F, 
        random.color = T, colors = palete)
cs

5. 결 과

   


7월 달에 여자친구가 시험때문에 같이 한숨을 많이 쉬었던지라 ㅋㅋㅋ 에휴가 1등이다 ㅋㅋㅋ

그외에도 곡성을 보고나서 뭐시중헌디 뭐시중헌디 거렸던것이  임팩트가 있었나보다..ㅋㅋ

차후에 다른 그래프로도 표현을 해보고 매달마다 자동적으로 분석해주는 프로그램을 만들어보고 싶다.

,