딥러닝에서 클래스 불균형을 다루는 방법


현실 데이터에는 클래스 불균형 (class imbalance) 문제가 자주 있다. 어떤 데이터에서 각 클래스 (주로 범주형 반응 변수) 가 갖고 있는 데이터의 양에 차이가 큰 경우, 클래스 불균형이 있다고 말한다. 예를 들어, 병원에서 질병이 있는 사람과 질병이 없는 사람의 데이터를 수집했다고 하자. 일반적으로 질병이 있는 사람이 질병이 없는 사람에 비해 적다. 비단 병원 데이터뿐 아니라 대부분의 "현실 데이터" 에 클래스 불균형 문제가 있다. 


클래스 균형이 필요한가?


왜 데이터가 클래스 균형을 이루어야할까? 그리고 언제 클래스 균형이 필요할까? 핵심은 다음과 같다. 클래스 균형 클래스 균형은 소수의 클래스에 특별히 더 큰 관심이 있는 경우에 필요하다. 


예를 들어 현재 재정 상황 및 집의 특성 등을 토대로 집을 사야할지 말아야할지를 예측하는 모델을 만들고 싶다고 하자. 사지말라고 예측하는 것과 사라고 예측하는 것은 그 무게가 다르다. 집을 사라고 예측하는 것은 훨씬 더 큰 리스크를 수반한다. 잘못된 투자는 큰 손실로 이루어질 수 있기 때문이다. 따라서 '집을 사라' 라고 예측하는 것에 대해서는 더 큰 정확도를 가져야한다. 하지만 데이터가 '집을 사지마라' 클래스에 몰려있는 경우, '집을 사지마라' 예측에 있어서는 높은 정확도를 가질 수 있어도 '집을 사라' 라고 예측하는 것에 관해서는 예측 성능이 좋지 않게 된다. 따라서 클래스 불균형이 있는 경우, 클래스에 따라 정확도가 달라지게 된다. 이를 해결하기 위해서는 따라서 '집을 사라' 클래스에는 더욱 큰 비중 (weight) 를 두고 정확한 예측을 할 수 있도록 만들어야한다.   


만약 소수 클래스에 관심이 없다면 어떻게 할까? 예를 들어, 이미지 분류 문제를 예로 들어보자. 그리고 오직, 전체 예측의 정확도 (accuracy) 에만 관심이 있다고 하자. 이 경우에는 굳이 클래스 균형을 맞출 필요가 없다. 왜냐하면 트레이닝 데이터에 만에 데이터를 위주로 학습하면, 모델의 정확도가 높아질 것이기 때문이다. 따라서 이런 경우에는 소수 클래스를 무시하더라도 전체 성능에 큰 영향을 주지 않기 때문에, 클래스 균형을 맞추는 것이 굳이 필요하지 않다고 할 수 있다. 


클래스 균형이 필요한 상황과 불필요한 상황을 예로 들어 설명했다. 다음으로는 딥러닝에서 클래스 균형을 맞추기 위한 두 가지 테크닉을 소개한다. 


(1) Weight balancing


Weight balancing 은 training set 의 각 데이터에서 loss 를 계산할 때 특정 클래스의 데이터에 더 큰 loss 값을 갖도록 하는 방법이다. 예를 들어, 이전 예에서 집을 사라는 클래스에 관해서는 더 큰 정확도가 필요하므로, 트레이닝 할 때, 집을 사라는 클래스의 데이터에 관해서는 loss 가 더 크도록 만드는 것이다. 이를 구현하는 한 가지 간단한 방법은 원하는 클래스의 데이터의 loss 에는 특정 값을 곱하고, 이를 통해 딥러닝 모델을 트레이닝하는 것이다.  


예를 들어, "집을 사라" 클래스에는 75 %의 가중치를 두고, "집을 사지마라" 클래스에는 25 %의 가중치를 둘 수 있다. 이를 python keras 를 통해 구현하면 아래와 같다. class_weight 라는 dictionary 를 만들고, keas model 의 class_weight parameter 로 넣어주면 된다. 


import keras

class_weight = {"buy": 0.75,
                "don't buy": 0.25}

model.fit(X_train, Y_train, epochs=10, batch_size=32, class_weight=class_weight)


물론 이 값을 예를 든 값이며, 분야와 최종 성능을 고려해 가중치 비율의 최적 세팅을 찾으면 된다. 다른 한 가지 방법은 클래스의 비율에 따라 가중치를 두는 방법인데, 예를 들어, 클래스의 비율이 1:9 라면 가중치를 9:1로 줌으로써 적은 샘플 수를 가진 클래스를 전체 loss 에 동일하게 기여하도록 할 수 있다. 


Weight balancing 에 사용할 수 있는 다른 방법은 Focal loss 를 사용하는 것이다. Focal loss 의 메인 아이디어는 다음과 같다. 다중 클래스 분류 문제에서, A, B, C 3개의 클래스가 존재한다고 하자. A 클래스는 상대적으로 분류하기 쉽고, B, C 클래스는 쉽다고 하자. 총 100번의 epoch 에서 단지 10번의 epoch 만에 validation set 에 대해 99 % 의 정확도를 얻었다. 그럼에도 불구하고 나머지 90 epoch 에 대해 A 클래스는 계속 loss 의 계산에 기여한다. 만약 상대적으로 분류하기 쉬운 A 클래스의 데이터 대신, B, C 클래스의 데이터에 더욱 집중을 해서 loss 를 계산을 하면 전체적인 정확도를 더 높일 수 있지 않을까? 예를 들어 batch size 가 64 라고 하면, 64 개의 sample 을 본 후, loss 를 계산해서 backpropagation 을 통해 weight 를 업데이트 하게 되는데 이 때, 이 loss 의 계산에 현재까지의 클래스 별 정확도를 고려한 weight 를 줌으로서 전반적인 모델의 정확도를 높이고자 하는 것이다. 



Focal loss 는 어떤 batch 의 트레이닝 데이터에 같은 weight 를 주지 않고, 분류 성능이 높은 클래스에 대해서는 down-weighting 을 한다. 이 때, gamma (위 그림) 를 주어, 이  down-weighting 의 정도를 결정한다. 이 방법은 분류가 힘든 데이터에 대한 트레닝을 강조하는 효과가 있다. Focal loss 는 Keras 에서 아래와 같은 custom loss function 을 정의하고 loss parameter 에 넣어줌으로써 구현할 수 있다. 

import keras
from keras import backend as K
import tensorflow as tf

# Define our custom loss function
def focal_loss(y_true, y_pred):
    gamma = 2.0, alpha = 0.25
    pt_1 = tf.where(tf.equal(y_true, 1), y_pred, tf.ones_like(y_pred))
    pt_0 = tf.where(tf.equal(y_true, 0), y_pred, tf.zeros_like(y_pred))
    return -K.sum(alpha * K.pow(1. - pt_1, gamma) * K.log(pt_1))-K.sum((1-alpha) * K.pow( pt_0, gamma) * K.log(1. - pt_0))

# Compile our model
adam = Adam(lr=0.0001)
model.compile(loss=[focal_loss], metrics=["accuracy"], optimizer=adam) 


(2) Over and under sampling


클래스 불균형을 다루기 위한 다른 방법은 바로 샘플링을 이용하는 것이다.


Under and and Over Sampling


예를 들어, 위 그림에서 파란색 데이터가 주황색 데이터에비해 양이 현저히 적다. 이 경우 두 가지 방법 - Undersampling, Oversampling 으로 샘플링을 할 수 있다. 


Undersampling 은 Majority class (파란색 데이터) 의 일부만을 선택하고, Minority class (주황색 데이터) 는 최대한 많은 데이터를 사용하는 방법이다. 이 때 Undersampling 된 파란색 데이터가 원본 데이터와 비교해 대표성이 있어야한다. Oversampling 은 Minority class 의 복사본을 만들어, Majority class 의 수만큼 데이터를 만들어주는 것이다. 똑같은 데이터를 그대로 복사하는 것이기 때문에 새로운 데이터는 기존 데이터와 같은 성질을 갖게된다.  


Reference

https://towardsdatascience.com/handling-imbalanced-datasets-in-deep-learning-f48407a0e758

https://towardsdatascience.com/methods-for-dealing-with-imbalanced-data-5b761be45a18

영어 학술 프리젠테이션에서 자주 쓰는 문구 정리


본 포스팅에서는 학술 영어의 특징과 영어 학술 프리젠테이션에서 자주 쓰이는 문구를 정리해보고자 합니다. 물론 중요한 것은 내용이겠지만 자주 쓰이는 표현을 익혀둔다면, 내용과 내용사이의 연결을 매끄럽게 할 수 있을 것이고, 전달력 좋은 프리젠테이션을 할 수 있을 것입니다. 


학술 영어의 특징


학술 영어의 특징은 아래와 같이 정리해볼 수 있습니다. 
  • 학술영어는 구어체보다는 형식적인 언어를 사용한다. 
  • I 를 피하고, 제 3자의 입장인것처럼 쓴다. (수동태를 많이 쓴다.)
  • 객관적이고, 공정한 표현을 쓴다.
  • 단정적인 표현을 삼가하고, 조심스러운 표현을 많이 쓴다. 

아래에 프리젠테이션의 각 단계 별로 자주 쓰이는 표현을 정리하였으며, 내용들은 https://englishforuniversity.com 을 참고하여 작성 되었습니다. 

Introduction


Greeting your audience, introducing yourself and giving the topic of your presentation. 

  • My name’s ............. and I’m going to talk about ... 
  • Good morning everybody. 
  • Thank you for coming to my talk today. 
  • My name is …… and I’m from ... 
  • Hello. I’m .............. and welcome to my presentation about ...
  • Hello. My name’s .................... and today I’m going to be talking about ... 
  • I’d like to start by introducing myself. 
  • My name’s … and the topic for my presentation today is … 
  • The theme of my talk is … 
  • My presentation this morning concerns … 
  • This afternoon I would like to talk to you about … 
  • I shall be looking at the following areas:… 
  • What I’d like to do is to discuss ... 
  • I intend to discuss ... 
  • I hope to consider the main issues around ... 
  • This morning I am going to talk about an issue which concerns everyone … 
  • This presentation focuses on the issue of…


Justifying the topic of your presentation

  • There are many concerns regarding … 
  • … has been the subject of much debate recently and this is the topic of my presentation.
  • Recent research has shown that… 
  • Did you know...........? This is the reason for my talk today. ... 
  • and this is the theme for my presentation today. 
  • … so the purpose of my presentation today is to inform/discuss/present/analyse … 
  • … is a growing problem in the world. For this reason I intend to focus on the issue of …


Giving the outline of your presentation

  • Firstly, I’m going to look at ... 
  • Secondly, I’ll move on to the issue of ... 
  • Then I’ll move on to examine ... 
  • Lastly/Finally, I’ll look at / focus on ...
  • I have divided my talk into the following main areas: ... 
  • I am going to divide my presentation into two main parts. First I’m going to describe … 
  • and then I’ll move on to look at … 
  • And in this part of my presentation I’ll be showing you some data/charts/tables … 
  • I’ll also try to explain my findings … 
  • In the third part of my presentation I’ll put forward some ideas about … 
  • I’ll also be offering some recommendations on how we can solve/address/tackle the issues of … 
  • ...then I’m going to suggest some possible measures to solve these difficulties. We’ll finish off with a question and answer session. 
  • My talk will last about ........... minutes and there’ll be time at the end for questions. 
  • At the end of my talk, which will last about ten minutes, I’ll be happy to answer any questions you may have.
  • If you have any questions please do not hesitate to ask. 
  • Please just put your hand up if you would like to ask a question. 
  • I’d like the presentation to be as interactive as possible, so please chip in as we go along. 
  • I’ve got quite a lot to get through, so I’d appreciate it if you kept your questions until the end of the presentation. 
  • I’m happy to let you have any of the slides or information in my presentation if you would like. 
  • If you leave your contact details I’ll be happy to send you any of the information here. 


Main Parts


Introducing your first main point 

  • Now, I’m going to start by … 
  • Now I’d like to focus on … 
  • First we’re going to look at … 
  • Let’s start with … 
  • The first problem I’d like to focus on is that of … 
  • Turning then to my first point, ... 
  • To begin with I’d like to say a few things about… 
  • I’d like to begin by … 
  • OK, so let’s start by looking at .... 
  • I’d like to take a minute or two to define what exactly we mean by ... 
  • I’d like to mention three points here, ...


Referring to research

  • Researchers have identified three key issues here, they are … 
  • Researchers have shown quite conclusively that … 
  • A number of recent studies, notably the ones by … and …, have shown that … 
  • A number of studies have shown that ... 
  • A study by … shows that ... 
  • Research suggests/indicates that … 
  • According to … Figures from … show/suggest/indicate that ... 
  • A very interesting study by … shows that… 
  • The study by … is on your reading list and I encourage you to take a look at it. 
  • Basically, what he found was that … 
  • One of the most interesting studies carried out in this area by … showed that …


Referring to visual data

  • If you look at this table you can see that ... 
  • The data here shows that... 
  • Please take a handout and pass them on. 
  • There are some handouts coming round on … 


Presenting a point of view

  • Those in favour of … argue that … 
  • Advocates of … claim that ... 
  • Some people claim that … but others … 
  • Most people/scientists would argue that … 
  • I think it’s fair to say that ... 
  • Personally, I think there is overwhelming evidence that ... 
  • Evidence does seem to show that ...


Analysing an argument

  • Let’s take a closer look at the argument put forward by ... His main contention is that ... but he fails to consider ... 
  • Even if we accept the point that ... that still leaves the question of ... 
  • The argument put forward by ... doesn’t explain ... 
  • The weakness in this argument is that ... 
  • This point of view is very appealing because ...


Emphasizing important points

  • It must be remembered that … 
  • It should be emphasised that … 
  • I would like to draw your attention to this point …


Losing your way

  • Now, where was I? Oh yes, … 
  • If you’ll bear with me for a moment while I just glance at my notes, right, … 
  • Erm, I’ll just need a minute to sort out the technology and I’ll be with you ... 


Moving to another main point

  • OK, so now I’d like to turn to my next point, which is ... 
  • Moving on, I’d like to take a look at …. 
  • Now I’d like to move on to ... 
  • Now let’s turn to the issue of ... 
  • I’ll come back to that issue later... 
  • I want to turn now to ... 
  • Turning now to ... 
  • Moving on now to ... 
  • Having looked at ….. 
  • let’s now think about ... 
  • My next point is in regards to … T
  • hat brings me to … 
  • My final point is in regard to…


Making recommendations

  • Now I’d like to look at some of the measures that can be taken to alleviate the problems of … 
  • In order to solve these problems, the following action should be considered: ... 
  • Firstly, the government should … 
  • The most important thing that should be done to combat the problem of ... is... 
  • Other possible solutions would be to ...


Conclusion


Making conclusions and summarising your main points 

  • To conclude my presentation, ... 
  • In conclusion, ... 
  • To summarise the main points of my presentation … 
  • In view of the evidence I have presented I think it is fair to say that … 
  • After all is said and done I think we can conclude that … 
  • This is clearly a very complex issue but on the strength of the evidence I have seen I would say that …/it seems that …


Finishing your presentation

  • OK we’re coming to the end of the presentation so I’d just like to thank you for listening ... 
  • OK. That bring us to the end of my presentation. 
  • Thank you for listening. 
  • I hope you found it interesting. 


Questions


Asking for questions 

  • Would anyone like to ask any questions? 
  • I’m ready to take any questions now. 
  • If anyone has questions I’ll be happy to answer them. 


Answering questions

  • Thanks for your question ... 
  • Good question. I think ... 
  • That’s an interesting question! As I see it ... 
  • Yes, that’s an interesting point ...

Dealing with difficult questions 

  • Hmm, that’s a good question. I don’t have the information to answer that question right now, but I’d be happy to find out and get back to you later. 
  • I don’t think we have enough time to go into that right now, but I’ll be happy to speak to you one-to-one after the presentation if you would like. 
  • That’s an interesting point, but I do think I have shown that ... 


Asking questions to the presenter

  • Excuse me. Can you say a bit more about ... 
  • Can you repeat your point about ... 
  • Excuse me. I have a question about ...
  • I didn’t catch what you said about .... 
  • Can you repeat it please? 
  • Are you saying that ...? 
  • Can you suggest some reading on that topic?



출처

https://englishforuniversity.com


Presentation phrasebook.pdf


Adaptive Histogram Equalization 이란 무엇인가? 


Adaptive Histogram Equalization (AHE) 이란 이미지 전처리 기법으로 이미지의 contrast 를 늘리는 방법이다. Histogram Equalization (HE) 방법을 조금 더 개선해서 만든 방법이라고 할 수 있는데, 그 차이점은 HE 는 하나의 histogram 을 통해 uniform 분포를 가정한 equalization 을 수행하는 반면, AHE 는 여러개의 histogram 을 만든다는 차이점이 있다. HE 의 문제점은 하나의 histogram 으로 pixel intensity 의 redistribution 을 수행하므로, pixel intensity 의 분포가 이미지의 전 범위에 걸쳐서 동일해야 적절히 수행될 수 있는 방법이다. 만약 이미지의 일부분이 다른 지역과 비교해 다른 분포를 갖고 있을 경우, HE 를 적용한 이미지는 왜곡된다. 




AHE 방법은 이미지를 grid 를 이용해서 여러 개로 쪼개고 이 쪼갠 이미지에 대해서 각각 HE 를 적용한다. 따라서 그 grid 안에서 이미지의 contrast 가 좋아지기 때문에 이미지의 local contrast 를 조정하기에 좋은 방법이라고 할 수 있다. 위 그림처럼 어떤 pixel 의 AHE 를 적용한 값은 각 box 안에서 HE 를 수행한 값이다. 경계에 위치한 pixel 에 대한 transformation 은 특별하게 다루어지는데, 그 반대편에 위치한 pixel 값들을 mirroring 함으로써 가상의 픽셀 값을 만든 후, AHE 를 적용하게 된다. 


AHE 의 단점은 어떤 grid 안에 있는 pixel intensity 들이 매우 좁은 지역에 몰려있는 경우에 발생한다. 이 경우 AHE 는 매우 좁은 지역에 위치해 있는 pixel intensity 들을 넓은 지역으로 퍼트리기 때문에 이 안에 다른 지역과 매우 작은 차이를 보이는 noise 가 있다고 하더라도 상당한 크기의 peak 를 만들어내게 된다. 예를 들어, 8x8 grid 안에서 하나의 pixel 이 1이고 나머지는 0인 경우, 1이 255로 변환이 되게 된다. 즉, 의미 없는 pixel 의 값이 크게 변화되는 문제가 생긴다. 이를 noise amplification 이라고 부르기도 한다. 또한 의미없는 지역의 pixel intensity 를 enhance 시키기도 한다. 즉, 이로 인해 원래 이미지에 왜곡이 생기게된다. 


Contrast Limited Adaptive Histogram Equalization 



Adaptive Histogram Equalization 과 늘 따라다니는 것이 Contrast limited adaptive histogram equalization (CLAHE) 방법이다. 이 방법은 AHE 의 변형으로 AHE 의 중대한 문제점인 noise amplification 을 해결하기 위해 contrast limit 을 활용한다. 만약 pixel intensity 가 좁은 구역에 몰려있다면, 아래와 같은 두 가지 현상이 생긴다. 


  1. 그 부근에서 slope of cdf 가 급격하게 증가한다.

  2. histogram의 높이가 매우 높다.


1, 2 는 결국 같다. slope of cdf 가 급격하게 증가하는 부분이 histogram 의 높이가 높은 지점이다. 따라서 CLAHE 방법은 위 그림과 같이 cdf 를 계산하기 전에 histogram 에 높이에 제한을 걸어 특정 높이 이상에 있는 pixel 값들을 redistribution 하는 과정을 먼저 거치게 된다. 이 때 histogram 의 높이를 제한하는 값을 clip limit 이라고 부른다. redistribution 이후에, 다시 clip limit 의 값을 초과할 수 있는데, 이를 그대로 놔두고 할 수 있지만, 제거하고 싶은 경우, 반복적으로 redistribution 을 실시한 후, 초과하는 pixel 값들이 무시할만 한 정도까지 반복할 수 있다. 결국 이러한 과정은 cdf function 의 기울기가 너무 높지 않게 제한한다. 최종적으로 가상의 cdf 함수를 구할 수 있고, 이를 통해 HE 를 적용하면 CLAHE 를 적용한 이미지를 얻을 수 있다. 


그러면 이 이미지는 좁은 범위에 pixel intensity 가 몰려 있는 경우 생기는 noise 에 robust 하도록 만든다. 왜냐하면 몰려 있는 픽셀의 값을 redistribution 을 하기 때문에 급격한 기울기가 없는 cdf를 통해 pixel intensity 를 변환하기 때문에 noise 의 pixel intensity 를 너무 큰 값으로 변환시키지 않도록 만든다. 그렇기 때문에 CLAHE 를 실시한 후의 local region 의 pixel intensity 가 0~255 사이에 위치해 있는 것이 아니라, 더 좁은 범위에 몰려 있게 만들 수 있다. 즉 CLAHE 를 사용했을 때 장점은, contrast 가 낮은 지역에 위치한 noise 에 robust 하도록 변환함으로써, 변환된 이미지가 실제 이미지와 비슷한 특성을 갖도록 만드는 것이다. 


참고

https://en.wikipedia.org/wiki/Adaptive_histogram_equalization

실제 능력과 남이 보는 능력 


「어떻게 능력을 보여줄 것인가?」 작가 잭 내셔 (1979~)


사람은 진짜 능력이 아니라 보이는 능력으로 판단 받는다. 이 책에서는 이를 2007년 최고의 바이올린 연주자인 조슈아 벨이 길거리에서 바이올린 연주를 하도록 한 실험을 통해 소개하였다. 유명한 연주자가 출근길 지하철에서 바이올린을 연주를 해도, 아무도 멈춰서서 그것을 감상하지 않았다. 이 실험에서 말하고자 하는 것은 아무리 최고의 능력을 갖고 있는 사람이더라도, 이 능력을 포장하지 않으면 사람들은 훨씬 덜 좋은 평가를 내린다는 것이다. 


실제 능력과 남이 보는 능력 (perceived competence)은 다르다. 이 책은 어떻게 하면 능력을 '포장' 해서 능력있고, 가치있어 보일 수 있는지에 대한 구체적인 방법을 제시한다. 사람은 '보이는 능력' 에 의해 평가 받기 때문에 능력을 잘 포장하는 것은 사회적 평판을 높일 수 있는 길이다. 


챕터 구성


1. 능력 있다는 평가를 이끌어 내는 법

2. 의심 많은 상사도 나를 믿게 하는 법

3. 나의 장점만 떠오르게 만든는 법

4. 운과 재능을 내 편으로 만드는 법

5. 마음을 훔치는 말하기 비법

6. 열마디 말보다 강력한 몸짓 사용법

7. 볼수록 매력 넘치는 사람들의 비밀

8. 아무도 흉내낼 수 없는 아우라는 만드는 법

 

이 책은 어떻게 능력을 보여줄 것인가? 라는 물음에 대해 위의 8개의 챕터로 구성하여 각 챕터에 대한 명확한 가이드를 제공한다. 본 포스팅에서는 이 중에서 몇 가지 인상 깊었던 부분을 정리해보려고 한다. 


열심히 일하는 것과 유능해 보이는 것


열심히 일하는 것은 나의 사회적 평판을 좋게하지 못할까? 이 책은 그렇지 않다고 말한다. 열심히 일하는 것이 중요하지 않다는 것은 아니다. 하지만 더 중요한 것은 "일을 잘해보이는 것" 이다. 사람들은 내가 열심히한 것에 관심이 없다. '내가 한 일' 이 아니라 '유능해 보이는지' 를 통해 평가하는 경우가 많다. 동일한 일이라고 하더라도, A 라는 사람은 열심히 밤을 새워 결과를 냈고, B 라는 사람은 대충 놀면서 결과를 냈다고 했을 때, 대부분의 사람은 B를 더 유능하게 평가한다. 즉, 동일한 결과물이 있을 때 '열심히 했다는 것' 은 오히려 그 사람의 유능함을 평가하는데 반대로 작용한다. 


신뢰성 있게 내가 한 것을 전달하는 방법


이 책의 모든 부분이 이러한 물음에 대한 간접적인 해법이 될 것이다. 하지만 챕터 5 의 어떻게 말하는 것이 사람의 마음을 움직이고 신뢰성 있게 보일 수 있는지에 대해 많은 도움을 줄 것이라 생각한다. 


  • 자신의 주장을 복잡하게 만들고, 숫자로 뒷받침하면 도움이 된다. 
  • 파워토킹을 할 것. 더듬는 말투, 과장된 존대법 등 군더더기를 걷어낼 것. 
  • 명료한 발음과 정확한 분절에 주의할 것.
  • 보통보다 조금 빠른 속도로 말해라.
  • 단조롭게 말하지 말고, 높은 어조와 낮은 어조를 번갈아 사용해라.
  • 보통보다 조금 더 큰 목소리로 말해라.
  • 자주 대화에 참여하되, 중간 정도의 시간을 써라.
  • 가장 중요한 논지를 내세우기 직전에 잠깐 침묵할 것!
  • 했던 말을 여러 번 되풀이하지 마라.
  • 상대방의 말을 끊지 마라.
  • 가능한 한 다양한 어휘를 사용해라.
  • 사투리는 충성심, 정직성 등을 어필해야 하는 경우에만 유리하다. 


첫 번째, '자신의 주장을 복잡하게 만들라.' 라는 것이 다소 직관과 거리가 멀어 보인다. 자신의 의견을 명료하게 말하면 듣는 사람에게 더 도움을 줄 수 있지 않을까? 하지만 말하기나 글쓰기의 목적이 단지, '능력있게 평가받기 위해서' 라면 자신의 주장을 다소 복잡하게 만들어, 듣는 사람이 이를 '스스로' 이해하게 만드는 것이 좋다는 것이 이 책의 주장이다. 


'파워토킹' 이라는 것은 '불필요한 요소' 가 없는 말하기를 말한다. 이 책에서 언급한 5가지 군더더기는 '강조하기', '망설임', '확인', '과도한 존대', '부가 의문문' 이다. 이러한 불필요한 요소가 많은 낮은 교육 수준 및 무능함을 연상시킨다. 즉,이러한 '군더더기'의 여부는 사회적 지위를 연상시키는 것으로 작용한다는 것이다 (참고). 


행동과 사회적 지위 평가


위의 '파워토킹' 의 예처럼, 사람의 행동은 사회적 지위를 평가하는 기준이 되기도 한다. 이 책의 챕터 8 '아무도 흉내낼 수 없는 아우라를 만드는 법' 에서는 어떻게 자신의 품격을 높이거나 높은 사회적 지위를 연상시키는 행동을 할 수 있는지에 대한 가이드를 제시한다. 

  • 관례를 따르지 않는 파격이 긍정적인 효과를 가져올 수도 있다. 단, 당신이 이미 높은 지위를 누리고 있는 경우에만!
  • 옷과 같이 당신을 둘러싼 모든 물건을 신중하게 고를 것.
  • 지루한 싸움을 피하고, 싸우기 좋아하는 사람들을 화해시켜라.
  • 남들이 너무 쉽게 접근하게 하지 마라.
  • 졸업장, 자격증, 상장 등을 눈에 띄게 전시할 것.
  • 가능한 한 전문 분야의 책을 집필해라.
  • 당신의 지적인 면모를 보여줄 '교양 게임' 을 벌일 것.
  • 높은 지위의 사람, 기관들과 함께 연상되도록 해라.
  • 권위를 지닌 존재와의 공통점을 만들어라.
  • 당신과 관계가 있는 모든 것을 찬양해라.


관례를 따르니 않는 파격적 등장에 관한 것은 '빨간 하이힐 효과' 를 예로 들 수 있다. 사람들은 오히려 후줄근한 모습으로 다니는 사람에 대해 유능하고 사회적 지위가 높은 사람이라는 평가를 내리기도 한다. 오히려 깔끔한 정장을 입고 다니는 사람에게는 상식과는 반대로 무능하다고 평가한다. 그리고 이러한 역설적인 평가는 '지적으로 뛰어난 집단 (혹은 적어도 자신이 똑똑하다고 생각하는 집단)' 으로 갈수록 그 경향이 심해진다.  빨간 하이힐 효과의 예는 많이 찾아볼 수 있다. 대표적으로 마크 저버커그는 맨발에 삼선 슬리퍼를 신고 다보스포럼 (세계 경제 포럼) 에 등장했다. 학회에서는 가장 많은 성과를 낸 학자들이 가장 편안한 복장으로 학회에 나타난다는 연구 결과도 있다. 왜 빨간 하이힐 효과가 발생할까? 핵심은 '관습과의 불일치' 이다. 관습과의 불일치는 '독립성' 을 의미하며, 이러한 개인주의와 독립성은 더 높은 지위와 능력을 연상시켜, 보이는 능력을 직접적으로 높인다. 다만, 이 책에 의하면 이미 어느정도 높은 지위를 누리고 있을 때, 이러한 '관습과의 불일치' 가 효과를 발휘한다. 


이외에도 이 책에 나온 내용 중 인상 깊은 것은 행동의 품격을 높이기 위해서 사소한 실수를 줄이라는 것이다. 하위 계층임을 암시하는 한 마디, 몸짓 하나에 보이는 능력이 땅으로 떨어질 수 있다. 물론 반대의 경우도 많다. 우선 자신의 거동을 면밀히 검토하고, 자신이 되고 싶은 사람의 거동과 행동을 자신의 것으로 만들면, 그에 걸맞는 대접을 받을 수 있다. 이와 관련해서 챕터 2에서 언급한 해리 벡위드의 말을 인용하고 싶다. '가장 좋은 선택지가 되려 하지 말고, 당신을 나쁜 선택지로 만들만한 모든 것을 없애라.' 



한 분야의 전문가로 인정받고 싶다면


이 책의 챕터  2에서는 직업적 측면에서 어떻게 인정받을 수 있는지에 대해 말하고 있다. 우선 '겸손' 에 대해 서술한 부분은 '어떻게 잘 겸손 할 수 있을까?' 에 대한 가이드를 준다. 때론, 겸손함은 불확실함 및 비겁함과 동일시되며, 실패에 대한 방어라고 해석되기도 한다. 겸손함이란 종종 그 목적이 자신을 향한 비판을 막으려는 계산에서 나오기 때문이다. 예를 들어, 프리젠테이션 도중 지나치게 겸손하며, 발표가 끝난 후, '충분한 준비를 하지 못해 죄송하다.' 라고 하는 경우, 사람들은 그를 겸손한 프로페셔널로 기억하지 않는다. 이 책에서는 겸손에 대해 '필요한 날에만 걸고 다니는 장신구' 라고 표현한다. 겸손은 필요할 때만 사용하면 되는데, 절대 자신의 핵심 능력을 방해하지 않는 선에서 해야한다. 자신의 직업 영역에서 겸손한 것은 오히려 보이는 능력을 하락시킨다. 


아무도 의사가 되고 싶었던 회계사를 높게 쳐주지 않는다. 남에게 자신이 능력있고 전문성 있는 사람으로 보이고 싶다면 Born to be 임을 어필하는 것이 좋다. 어떠한 직업군에 대한 고정관념이 있다. 예를 들어, 우리는 학자는 산만하고 괴짜이며, 변호사는 이성적이고, 유창한 언변을 갖추었을 것이라고 생각한다. 어떤 사람들은 직업에 대한 고정관념을 깨고 싶어, 그와 정반대 되는 모습을 드러내려고 하는 사람들이 있다. 이와 관련해서는 챕터 4에 나온 '애완견이 되고 싶었던 당나귀' 이야기를 언급하고 싶다.


당나귀는 저녁마다 우리에 서서 자고, 하루 종일 주인을 위해 열심히 일해야 했다. 그에 반해 애완견은 집안에서 잠을 자고, 아무 일도 하지 않아도 맛있는 사료와 간식을 먹었다. 그 모습을 본 당나귀는 주인에게로 달려가 애완견처럼 꼬리를 흔들고, 그의 가슴으로 뛰어오르려 했다. 놀란 주인은 당나귀를 우리에 더욱 단단히 묶어 두었다. 


이 이야기 말해주듯, 세상은 감상에 젖어 본분을 잊어버린 변호사를 바라지 않는다. 자신의 직업군에 관해 사람들이 기대하는 바를 잘 알고, 그에 맞게 행동하는 이들은 같은 일을 해도 더욱 많은 결실을 건져 올리게 된다. 만약, IT 에 종사하는 사람이라면, 스마트 워치를 차고, 스마트 태블릿에 메모를 하라. 이는 보이는 능력을 높여줄 것이다. 



정리


이 책은 보이는 능력을 키울 수 있도록 실제로 일상 생활에서 실천할 수 있는 것을 명확하게 열거하고 있다. 많은 사람들이 노력을 통해 자신의 전문성을 키우고, 남한테 인정받는 사람이 되고자 한다. 이 책은 능력으로 인정받고 싶은 사람들에게 보이는 능력을 높임으로써 더욱 쉽게 인정받을 수 있는 방법을 제시했다고 생각한다. 한 편, 이 책의 내용은 어떤 면에서는 다소 불쾌한 느낌이 들 수도 있다고 생각한다. '상위 계층' 과 '하위 계층' 을 나누어서 상위 계층으로 가기 위한 방법을 설명하고 있는듯 하다는 점 때문일 것이다. 하지만, 스스로 사회를 변화시키는 것은, 사회에 적응하는 것보다 힘들다. 사회를 변화시키는 더 쉬운 방법은 우선 사회에 적응해 자신처럼 생각하는 사람을 많아지게 하는 것일 것이다.  만약 내가 무언가가 간절히 되고 싶고, 이에 대한 암묵적인 사회적 규범이 존재한다면, 적어도 이를 파악하고 극복하기 위해 노력한다면 실제로 더 많은 보수를 가져다 줄 것이다. 


'Soft skills > Communication' 카테고리의 다른 글

어떻게 능력을 보여줄 것인가? - 잭 내셔  (0) 2019.06.01

Histogram Equalization 이란 무엇인가? 


IDEA



Histogram equalization (HE) 은 이미지를 전처리하는 방법이다. 위 그림만 보고도 HE 의 기본적인 아이디어를 알 수 있는데, HE 는 이미지의 contrast 가 적을 때 매우 유용하게 사용할 수 있는 방법이다. "Before Histogram Equalization" 이미지는 contrast 가 매우 떨어진다는 볼 수 있다. 오른쪽 histogram 을 보면 이미지 픽셀이 0~255에 고르게 퍼져있는 게 아니라, 일부분에 몰려있다는 것을 확인할 수 있다. "After Histogram Equalization" 을 보면, 이미지의 contrast 가 증가한 것을 확인할 수 있다. 이렇게 이미지의 밝기를 조정하는 것이 HE 로, HE 이후에는 밝기가 0~255 사이에 고르게 분포함을 알 수 있다. 이는 Cumulative density function (cdf) 을 통해 볼 수 있는데, 0~255 사이에서 cdf 가 일직선 형태를 나타내게 된다. 



Formula

L = 266 (일반적으로 0~255 사이에서 pixel intensity 를 표현하기 때문에)    


Example

 

HE 를 실제로 하는 방법은 해당 pixel intensity 의 cdf function 값을 구한 후, 0~255 사이의 uniform 분포에 맞게 값을 변환을 시켜서 넣어주면 된다. 예를 들어, 총 픽셀 수가 64 인 이미지가 있다고 하자 이 이미지에서 가장 낮은 pixel intensity 는 52 이다. 이를 어떻게 변환하는지를 보면 cdf(v) = 1, cdf_min = 1 MxN=64, cdf_min = 1, L-1 = 255 이고 분자가 0이므로 값은 0이 된다. pixel intensity 가 55 일 때, cdf(v) = 4, cdf_min = 1, MxN = 64 이므로, h(v) = 12 이다. cdf_min 은 cdf(v) 중 가장 작은 값으로 이 값을 분자 분모에서 빼주는 이유는 h(v) 를 0부터 시작하도록 하기 위함이다. 


v, Pixel Intensitycdf(v)h(v), Equalized v
5210
55412
58620
59932
601036
611453
621557
631765
641973
652285
662493
672597
6830117
6933130
7037146
7139154
7240158
7342166
7543170
7644174
7745178
7846182
7948190
8349194
8551202
8752206
8853210
9054215
9455219
10457227
10658231
10959235
11360239
12261243
12662247
14463251
15464255


참고

https://en.wikipedia.org/wiki/Histogram_equalization



Linearly weighted kappa 란 무엇인가?



Formula


$$ k_w = (P_0 - P_e) / (1 - P_e) $$



사용하는 이유


두 명의 측정자 (rater) 의 일치도를 평가 (inter-rater agreement) 할 때 쓰이며, 측정치가 순서가 있는 정성적 지표 (ordinal categorical variable) 일 때 쓰인다.  그냥 kappa coefficient 대신에 linearly weighted kappa 를 사용하는 이유는, 이러한 순서형 척도 변수에서 근접하게 측정된 값을 그냥 버리기 아깝기 때문에 이를 고려해서 일치도를 평가하기 위함이다. 


방법


P_0 =  proportion weighted observed agreement

P_e =  proportion weighted chance agreement


위의 두 값을 구하면 된다. 이를 위해 우선 아래와 같은 weight matrix 를 생성한다.  weight matrix는 측정치가 5개의 범주로 나누어지는 경우 아래와 같이 구할 수 있다. 



두 명의 측정자의 측정치가 아래와 같다고 한다. 예를 들어, 아래 테이블은 측정자 A와 측정자 B가 동시에 1이라고 판단한 경우는 8건이고 이는 전체의 0.07 이며, 측정자 A가 1, 측정자 B 가 2라고 판단한 경우는 2건으로 전체의 0.02 임을 의미한다.  





이 때, $$ P_0 = 0.07 * 1 + 0.02 * 0.75 + 0.009 * 0.5 + 0.026 * 0.75 + 0.09 * 1 ... + 0.02 * 1 = 0.93 $$ 로 구할 수 있다.


또한, $$ P_e =1 *(0.094 * 0.094) + 0.75 * (0.094 * 0.1709) + 0.50 * (0.094 * 0.530) ... + 0.02 * (0.0171*0.0171) = 0.78 $$ 로 구할 수 있다. 


결국 $$ k_w = (P_0 - P_e) / (1 - P_e) = (0.93 - 0.78) / (1 - 0.78) = 0.68 $$




Reference

http://www.anestesiarianimazione.com/DWLDocuments/The%20Linearly%20Weighted%20Kappa.pdf




R - Windows 에서 source 로부터 패키지 설치하기 



devtools 를 통해 최신 개발 버전의 tidyr 을 설치 



devtools::install_github("tidyverse/tidyr")

Downloading GitHub repo tidyverse/tidyr@master

Error: Could not find tools necessary to compile a package


그냥 설치하면 위와 같은 에러가 나오면서 설치되지 않음 


아래 옵션 추가함으로써 무엇이 잘못되었는지, 어떤 dependencies 를 설치할 때 오류가 발생한 것인지 확인 가능

options(buildtools.check = function(action) TRUE )


다시 아래 코드 실행 
devtools::install_github("tidyverse/tidyr")

These packages have more recent versions available.
Which would you like to update?

1:   rlang    (0.3.4 -> 6a232c019...) [GitHub]
2:   ellipsis (0.1.0 -> d8bf8a34e...) [GitHub]
3:   CRAN packages only
4:   All
5:   None

4. All 을 입력해줌 

WARNING: Rtools is required to build R packages, but is not currently installed.

Please download and install Rtools 3.5 from http://cran.r-project.org/bin/windows/Rtools/.


Rtools 가 소스를 컴파일할 때 필요함 


RTools 설치 - 버전에 맞는 R tools 를 설치함

https://cran.r-project.org/bin/windows/Rtools/


Rtools 폴더를 환경변수 걸기 

예를 들어 C:/Rtools 를 환경변수로 잡음


Permission denied error 가 뜰 수 있는데 공용폴더로 lib path 를 지정하면 된다.

아래처럼 공용 폴더에 install_github 를 통해 패키지를 설치할 수 있음 

with_libpaths(new = "C:/Program Files/R/R-3.5.3/library", install_github('tidyverse/tidyr')) 


결국 소스를 컴파일 하면서 잘 설치가 되는 것을 확인할 수 있음 


C:/Rtools/mingw_64/bin/g++  -I"C:/PROGRA~1/R/R-35~1.3/include" -DNDEBUG  -I"C:/Users/JuYoungAhn/Documents/R/win-library/3.5/Rcpp/include"        -O2 -Wall  -mtune=generic -c RcppExports.cpp -o RcppExports.o

C:/Rtools/mingw_64/bin/g++  -I"C:/PROGRA~1/R/R-35~1.3/include" -DNDEBUG  -I"C:/Users/JuYoungAhn/Documents/R/win-library/3.5/Rcpp/include"        -O2 -Wall  -mtune=generic -c fill.cpp -o fill.o

C:/Rtools/mingw_64/bin/g++  -I"C:/PROGRA~1/R/R-35~1.3/include" -DNDEBUG  -I"C:/Users/JuYoungAhn/Documents/R/win-library/3.5/Rcpp/include"        -O2 -Wall  -mtune=generic -c melt.cpp -o melt.o

C:/Rtools/mingw_64/bin/g++  -I"C:/PROGRA~1/R/R-35~1.3/include" -DNDEBUG  -I"C:/Users/JuYoungAhn/Documents/R/win-library/3.5/Rcpp/include"        -O2 -Wall  -mtune=generic -c simplifyPieces.cpp -o simplifyPieces.o


......


library("tidyr", lib.loc="C:/Program Files/R/R-3.5.3/")


이렇게 path 를 지정해주면 라이브러를 로딩할 수 있음


R 을 더욱 효율적으로 사용하는 방법 3가지



프로그래밍에서의 효율성 


프로그래밍에서의 효율성이란 아래와 같이 두 가지로 나누어볼 수 있다. 



- Algorithmic efficiency

: 컴퓨터가 어떠한 일을 얼마나 빠르게 수행할 수 있을지에 관한 것


- Programmer productivity

: 단위 시간동안 사람이 할 수 있는 일의 양 


부연 설명을 하자면, 만약 어떠한 코드를 R 이 아니라 C로 구현을 하면 100배 빠르다고 하자, 하지만 그 코드를 짜는데 100배 넘는 시간이 들고, 그것이 여러번 사용되지 않고 딱 한 번 사용되고 버려지는 코드라면 그 일은 아무런 의미가 없게 된다.



R 의 특수성


우선 효율적인 R 프로그래밍을 알아보기 전에 R 언어의 특징을 알아보자. 


- R 언어는 무언가를 해결하기 위한 다양한 방법을 제공한다. 

그것은 장점이 되기도 하고 단점이 되기도 한다. 단점이란 명확한 '정답' 이 없어 헤멜 수 있다는 것이고, 장점은 다양한 접근법을 시도할 수 있기 때문에 개인의 창의성이 발휘될 수 있다는 것이다. R 에서는 모든것이 생성된 후에 변형될 수 있다라는 말처럼 (“anything can be modified after it is created” - 해들리 위컴) R 은 매우 유연한 언어이다. 


- R은 컴파일 언어가 아니다. 하지만 컴파일된 코드를 call 할 수 있다. 

따라서 코드를 컴파일링하는 작업을 하지 않아도 된다는 장점이 있다. 한 편, 최대한 C나 FORTRAN 으로 컴파일된 코드를 call 하면 그만큼 빠른 속도의 증가를 불러올 수 있다. 또한 R 은 함수형 언어이며, 객체지향언어이기 때문에 같은 작업을 하는 code 를 짧게 쓸 수 있다는 특징이 있다.



Algorithmic efficiency in R


R 은 컴파일된 코드를 call 할 수 있기 때문에 R 의 Algorithmic efficiency 를 향상시키기 위한  Golden-rule  C/Fortran 에 최대한 빠르게 접근하는 것이다. 그걸 어떻게 하는지에 관한 것은 Efficient R Programming 에서 자세히 다루고 있다. 본 포스팅에서는 Programmer efficiency 에 대해서 간단하게 다루어 보려고 한다. 



Programmer efficiency in R


R에는 하나의 문제를 해결하기 위한 다양한 해결법이 있다. 예를 들어, data frame 의 subsetting 에서도 data$x 도 쓸 수 있고 data[['x']] 도 쓸 수 있다. 하지만 '결과를 중시하는 코딩' 을 하는 경우, 어떠한 문제를 해결할 '가장 효율적인 방법' 이 무엇인지 알기만 하면 된다. 본 포스팅에서는 이 관점에서 어떻게하면 R 을 통해 결과를 빠르고 생산성 있게 작성할 수 있는지에 대해 간단하게 정리해보려고 한다. 



1. Conding convention 을 사용해보자 


Good coding style is like using correct punctuation. You can manage without

it, but it sure makes things easier to read. - Hadley Wickham


위 말처럼 좋은 코딩 스타일을 갖는 것은 구두점을 정확하게 사용하는 것과 같다. 구두점이 없더라도 문장을 읽을 수는 있지만 구두점이 있다면 문장을 더 쉽게 읽을 수 있게 된다. 특히 일관적인 코딩 스타일은 협업을 할 때 중요하다. 협업을 하지 않고, 혼자 작업을 하더라도 자신의 코드를 오랜만에 보았을 때, 코딩 스타일이 일관적이라면 더 쉽게 이해할 수 있다. 


R 에는 공식 스타일 가이드가 없다. 하지만 R 커뮤니티는 이미 성숙도가 높기 때문에 유명한 coding convention 이 존재한다. 


Bioconductor’s coding standards (https://bioconductor.org/developers/how-to/coding-style/)

- Hadley Wickham’s style guide (http://stat405.had.co.nz/r-style.html )

- Google’s R style guide (http://google-styleguide.googlecode.com/ svn/trunk/google-r-style.html )

- Colin Gillespie’s R style guide (http://csgillespie.wordpress.com/2010/ 11/23/r-style-guide/)

The State of Naming Conventions in R (by Rasmus Bååth)


참고하면 좋을 자료 

https://www.r-bloggers.com/%F0%9F%96%8A-r-coding-style-guide/ 



2. 반복 작업을 짧고, 간결하게 작성하자


R Apply Family


R 에서의 반복작업을 할 때, Apply 계열의 함수 (Apply family 라고 부르기도 한다.) 를 이용하면 좋다. Apply 계열의 함수는 함수의 인자로 함수를 넣어주는 특징을 갖고 있다. 인자로 들어온 함수를 데이터에 대해 여러번 적용 시켜서 결과를 반환하는 것이다. Apply 계열의 함수를 이용하면 1) 빠르고, 2) 읽기 쉽다. 


1. Apply 계열의 함수는 C 코드로 되어있다. 비록, for 문의 성능이 최근들어 좋아졌다고 하더라도, Apply 계열의 함수가 더 빠르다.


2. '어떻게' 하는지가 아니라 '무엇을' 하는지에 대해서 강조할 수 있다. R 의 목적은, 프로그래밍이 아니라, 데이터를 Interactive 하게 탐구하는 것이다. Apply 계열의 함수를 이용하는 것은 R 언어의 본질적 특징인 Functional Programming 의 원칙에 부합하는 코딩 스타일이라고 할 수 있다. 


이와 관련해서는 이전 포스팅에 정리한적이 있다. 또한 다양한 책과 블로그에서 Apply family 에 관하여 잘 정리가 되어있으니 참고하면 좋다. 또한 이러한 Apply 계열의 함수는 R 고유의 문법이 아니다. Python 에서도 이와 비슷하게 함수를 input 으로 받아들이는 함수들이 있다. Map, Filter, Reduce 가 그것이다. 이에 대해서도 이전 포스팅에 정리한 적이 있다. 따라서 이러한 문법에 익숙해 진다면 다양한 프로그래밍 언어를 사용할 때, 훨씬 생산성을 높일 수 있다. 


Overview

FunctionDescription
applyApply functions over array margins
byApply a function to a data frame split by factors
eapplyApply a function over values in an environment
lapplyApply a function over a list or vector
mapplyApply a function to multiple list or vector arguments
rapplyRecursively apply a function to a list
tapplyApply a function over a ragged array


Purrr 


Tidyverse 의 멤버중 하나인 Purrr 을 이용하면 반복작업을 Apply family 에 비해 더욱 직관적이고 쉽게 할 수 있다.


Purrr 패키지는 고양이의울음소리를 의미하는 purr 과 r을 합친 의미로, 위와 같이 귀여운 로고를 가졌다. 아래는 공식 홈페이지에서 purrr 에 대한 설명이다. 


purrr enhances R’s functional programming (FP) toolkit by providing a complete and consistent set of tools for working with functions and vectors. If you’ve never heard of FP before, the best place to start is the family of map() functions which allow you to replace many for loops with code that is both more succinct and easier to read. The best place to learn about the map() functions is the iteration chapter in R for data science. 


Purrr 에서 가장 기본적인 함수는 map() 이다. map 이 어떻게 사용되는 지를 간단하게 알아보자. 


df 에서 a,b,c,d 의 평균을 출력하는 작업을 해보자. 


mean(df$a)

mean(df$b)

mean(df$c)

mean(df$d)


이를 반복문을 사용하면 아래와 같이 할 수 있다. 


for var in c("a", "b", "c", "d") {

print(mean(var), trim = 0.5)

}


map 함수를 사용하면 아래와 같이 할 수 있다. 


map_dbl(df, mean, trim = 0.5)

#>      a      b      c      d 
#>  0.237 -0.218  0.254 -0.133

두 접근법의 차이는 무엇일까? 


for 문을 사용한 것은 how 에 관한 정보를 포함하고 있지만 map 함수는 what 에 집중한다. 즉, 이 코드에서 하고자하는 것은 평균을 내는 것이다. R 은 그 작업을 "어떻게" 하는지에는 관심이 없다. map 을 사용하면 하고자 하는 작업인 '평균내기' 에 집중한 코드를 작성할 수 있다. 이와 관련해서는 Hadley Wickham 의 강의를 참고하기 바란다. 



3. 효율적인 Data Carpentry 를 하자 


데이터 처리를 일컫는 수많은 말이 있다. clean, hack, manipulation, munge, refine, tidy 등이다. 이 과정 이후에 modeling 과 visualization 을 수행하게 된다. 데이터 처리는 실제 재미있고, 의미 있는 작업을 하기 전에 수행되는 dirty work 로 생각되어지기도 한다. 왜냐하면 시간만 있으면 그것을 할 수 있다는 것이 한 가지 이유일 것이다. 하지만 데이터를 아주 깔끔하게 정돈하고, 원하는 형태를 빠르고 정확하게 만들어내는 것은 필수적인 능력이다.  또한 데이터처리 과정을 추상화해서 재생산 가능한 (reproducible) 코드를 만드는 작업은 단순 노동과는 다른 높은 숙련도를 가져야만 할 수 있는 것이다. 따라서 이러한 사람들의 인식은 틀렸다고 할 수 있다. 또한 미국에는 데이터 처리만 해서 판매하는 회사도 존재하며, 이 회사의 가치는 매우 높다! 이러한 데이터 처리 과정에 대해 Efficient R Programming 의 저자이자 유명한 R 교육자인 Colin Gillespie 와 Robin Lovelace는 Data Carpentry 라는 이름을 붙였다. 


Colin Gillespie 와 Robin Lovelace 가 정리한 효율 적인 Data Carpentry 를 위한 5가지 팁은 아래와 같다. 


1. Time spent preparing your data at the beginning can save hours of frustration in the long run.

2. ‘Tidy data’ provides a concept for organising data and the package tidyr provides some functions for this work.

3. The data_frame class defined by the tibble package makes datasets efficient to print and easy to work with.

4. dplyr provides fast and intuitive data processing functions; data.table has unmatched speed for some data processing applications.

5. The %>% ‘pipe’ operator can help clarify complex data processing workflows.


Data carpentry 는 크게 두 가지로 나눌 수 있다.  


Tidying : Raw 데이터를 "Tidy data" 로 만드는 작업 

Transformation: "Tidy data" 를 원하는 형태로 만드는 작업 (subsetting, adding column, summarizing 등)


대표적으로, Tidying 을 위한 패키지는 tidyr, Transformation 을 위한 패키지는 dplyr, data.table 패키지가 있다. 이 과정에서 Tibble 이라는 데이터 프레임을 상속한 클래스를 사용하면 데이터를 print 하거나, 처리할 때 있어 더욱 효율적이며 magrittr 의 pipe (%>%) 는 더욱 읽기 쉽고 직관적인 코드를 만든다. R 기본 패키지에 비해 dplyr 를 사용했을 때의 장점에 대해서는 이전 포스팅에 정리한 적이 있다. 필자 의견으로는 한 번도 dplyr 를 사용하지 않은 사람은 있어도, 한 번만 dplyr 를 사용한 사람은 없다고 생각될 정도로 dplyr 를 사용했을 때 높은 생산성을 가질 수 있다. 


예를 들어, 특정 행을 subsetting 하는 코드를 작성한다고 해보자. 


flights 라는 data frame 에서 arr_delay 가 120 미만인 행을 골라낸다고 하면, R 기본 subsetting 방법으로 하면 아래와 같다. [] 안에 logical vector 를 넣는 subsetting 방법이다. 문제는, is.na 를 이용해 arr_delay 가 na 인 경우도 고려해야한다는 것이다. 


flights[(flights$arr_delay < 120) & !is.na(flights$arr_delay), ]

하지만 dplyr 를 사용하면, 이러한 기술적인 것과 상관없이 직관적으로 코드를 작성할 수 있다. 


filter(flights, arr_delay < 120


R 커뮤니티의 최신 유행을 Follow 하기 좋은 방법 


R 커뮤니티의 성숙은 매우 빠르게 이루어지고 있고, 그러한 주류에 속하기 위해서는 뉴스를 빠르게 습득해야할 필요가 있습니다. 이와 관련하여 이전 글에서 R과 데이터과학의 트렌드를 알 수 있는 블로그들을 소개했습니다 


하지만 더욱 빠르게 정보를 습득할 수 있는 방법은 트위터의 rstats 해쉬태그를 이용하는 것입니다.  


https://twitter.com/hashtag/rstats?src=hash&lang=en&lang=en

해당 트윗에 들어가면 실시간으로 R 커뮤니티에 올라오는 새로운 소식들을 만나볼 수 있습니다. 



블로그나, 최신 책을 이용하는 방법도 있지만, 트위터는 몇 분마다 한 번씩 글이 올라오니 가장 최신 정보를 생생하게 알 수 있다는 장점이 있어 좋은것 같네요.



이외에도 다양한 트위터들이 있으니 Follow 하면 도움이 될 것 같습니다.]


또 Reddit 의 Rstats 페이지도있습니다. (https://www.reddit.com/r/rstats/)

Object Oriented Programming in R

R 베이스타입

  • 모든 베이스 R 개체는 그 객체가 메모리에 저장되는 방법을 기술하는 C 구조가 있다.
  • 베이스 타입은 R 코어팀만 만들 수 있다. 실제 객체 시스템은 아니다.
  • typeof 함수는 R base type 을 반환한다. (vector, list, function, builtin)
typeof(c("a")) # character vector 
#> [1] "character"
typeof(mean) # 함수는 closure
#> [1] "closure"
typeof(sum) # 원시함수는 built in 
#> [1] "builtin"
typeof(abs) # builtin 
#> [1] "builtin"
typeof(pnorm) # closure 
#> [1] "closure"
typeof(array(c(1.1, 2.2, 3.3), 3)) 
#> [1] "double"
typeof(matrix(1:3, 3)) 
#> [1] "integer"
df <- data.frame(x = 1:10, y = letters[1:10]) # dataframe 의 base type 은 list 이다. 
typeof(df)
#> [1] "list"

S3

  • S3는 가장 단순한 OO 시스템이고, base와 stats 패키지에서 사용된 유일한 OO 시스템이다.
  • CRAN 에 있는 많은 패키지들에서 가장 공통적을 사용되는 시스템이다.
  • pryr 패키지의 otype 함수는 해당 객체가 base type 그 자체인지 어떤 base type 에 기반한 S3 인지 S4 등 인지를 출력한다.
library(pryr)
df <- data.frame(x = 1:10, y = letters[1:10])
otype(df) # data frame은 S3 객체이다. 
#> [1] "S3"
otype(c("A")) # vector는 S3 객체가 아니다. R 베이스타입이다. 
#> [1] "base"
otype(c(1,2,3)) 
#> [1] "base"
otype(array(1:3, 3)) # array는 R 베이스타입이다.
#> [1] "base"
otype(matrix(1:3, 3)) # matrix 는 R 베이스타입이다. 
#> [1] "base"
otype(list(a=c(1:3))) # list 는 R 베이스타입이다. 
#> [1] "base"
otype(factor(1)) # factor는 S3 객체이다. 
#> [1] "S3"

S3 클래스 정의하기

# 한 번에 클래스를 생성하고 할당하기
# structuer(base object, class = class_name)
# structure 함수는 해당 attribute 를 갖는 객체를 만드는 함수이다. 
foo <- structure(list(), class="foo") 
foo
#> list()
#> attr(,"class")
#> [1] "foo"

# 클래스를 생성하고 난 후 설정하기
foo <- list()
class(foo) <- "foo"

상속 (Inheritance)

inherits(foo, "foo") # foo 객체가 foo class 를 상속하는지 체
#> [1] TRUE
  • 예를들어, glm 은 lm 클래스의 하위 클래스이다.
model <- glm(mpg ~ cyl + hp, data=mtcars) 
class(model) # glm class 는 이와 같이 상속받은 lm 클래스를 class 에 포함하고 있다. 
#> [1] "glm" "lm"
inherits(model, "lm") 
#> [1] TRUE
  • lm 에는 없고, glm 에는 있는 generic function 찾아보기
methods(class="glm") # lm 에 추가하여 glm 에 추가로 정의된 generic function 이다. 
#>  [1] add1           anova          coerce         confint       
#>  [5] cooks.distance deviance       drop1          effects       
#>  [9] extractAIC     family         formula        influence     
#> [13] initialize     logLik         model.frame    nobs          
#> [17] predict        print          residuals      rstandard     
#> [21] rstudent       show           slotsFromS3    summary       
#> [25] vcov           weights       
#> see '?methods' for accessing help and source code
methods(class="lm") 
#>  [1] add1           alias          anova          case.names    
#>  [5] coerce         confint        cooks.distance deviance      
#>  [9] dfbeta         dfbetas        drop1          dummy.coef    
#> [13] effects        extractAIC     family         formula       
#> [17] hatvalues      influence      initialize     kappa         
#> [21] labels         logLik         model.frame    model.matrix  
#> [25] nobs           plot           predict        print         
#> [29] proj           qr             residuals      rstandard     
#> [33] rstudent       show           simulate       slotsFromS3   
#> [37] summary        variable.names vcov          
#> see '?methods' for accessing help and source code

클래스의 생성자 만들기

  • 생성자 함수는 일반적으로 클래스와 동일한 이름을 갖도록 한다.
foo <- function(x) { 
  if (!is.numeric(x)) stop("X must be numeric")
  structure(list(x), class="foo")
}
  • 생성자를 통해 변수 생성하기
foo_var <- foo(c(1,2,3)) 
print(foo_var)
#> [[1]]
#> [1] 1 2 3
#> 
#> attr(,"class")
#> [1] "foo"
str(foo_var) 
#> List of 1
#>  $ : num [1:3] 1 2 3
#>  - attr(*, "class")= chr "foo"
typeof(foo_var)
#> [1] "list"
otype(foo_var)
#> [1] "S3"
class(foo_var)
#> [1] "foo"
length(foo_var) # length generic function 의 default 가 실행되며, 여기서 base type 이 list 임을 확인하고, list 의 길이 1을 반환한다.
#> [1] 1
  • R 에서는 기존 객체의 클래스를 변경할 수 있다.
mod <- lm(log(mpg) ~ log(disp), data = mtcars) 
class(mod) 
#> [1] "lm"
typeof(mod)  
#> [1] "list"
print(mod)
#> 
#> Call:
#> lm(formula = log(mpg) ~ log(disp), data = mtcars)
#> 
#> Coefficients:
#> (Intercept)    log(disp)  
#>      5.3810      -0.4586
  • lm 클래스에 데이터프레임 class 를 추가하기
class(mod) <- "data.frame"
print(mod) # data frame s3 method 를 호출한다. 
#>  [1] coefficients  residuals     effects       rank          fitted.values
#>  [6] assign        qr            df.residual   xlevels       call         
#> [11] terms         model        
#> <0 rows> (or 0-length row.names)
mod$coefficients
#> (Intercept)   log(disp) 
#>   5.3809725  -0.4585683

S3 새로운 메소드와 제너릭 생성하기

  • 새로운 제너릭을 만들고 싶을 대, UseMethod() 를 call 하는 function 을 만든다.
  • UseMethod 는 제너릭 메소드의 이름과, argument를 input 으로 받는다.
f <- function(x) UseMethod("f") # 이렇게하면 f 라는 이름의 제너릭이 생성된 것이다. 

# 제너릭은 메소드가 없다면 쓸모가 없다. 아래와 같이 제너릭 메소드를 구현할 수 있다.
f.a <- function(x) "Class a" 
a <- structure(list(), class = "a") 
class(a) 
#> [1] "a"
  • 제너릭 함수의 호출
f(a)
#> [1] "Class a"
  • 원래 있는 제너릭에 메소드를 추가하기
mean.a <- function(x) "a"
mean(a)
#> [1] "a"

메소드 디스패치

  • S3에서 메소드 디스패치하는 법은 심플하다.
  • default 메소드를 정의하면 해당 클래스에 대한 메소드가 없을 경우 실행됨
f <- function(x) UseMethod("f") 
f.a <- function(x) "Class a" 
f.default <- function(x) "Unknown class" 

f(structure(list(), class = "a"))
#> [1] "Class a"
# b메소드에 대한 메소드가 없기 때문에 a 클래스에 대한 행된다. 
f(structure(list(), class = c("b", "a")))
#> [1] "Class a"
# c class에 대한 메소드 구현이 없기 때문에 default 메소드가 실행된다.
f(structure(list(), class=c("c"))) 
#> [1] "Unknown class"
c <- structure(list(), class = "c")
# Call the correct method:
f.default(c)
#> [1] "Unknown class"
  • 다른 클래스의 제네릭 메소드를 실행할 수도 있다.
f.a(c)
#> [1] "Class a"
  • S3 object가 아닌 것도, S3 제너릭 메소드를 실행할 수 있다.
  • 이 경우 R base type 을 이용해 메소드를 실행한다.
  • 이 R base type 을 알아내는 것은 힘들 수 있지만 아래와 같은 함수로 가능하다.
iclass <- function(x) {
  if (is.object(x)) {
    stop("x is not a primitive type", call. = FALSE)
  }

  c(
    if (is.matrix(x)) "matrix",
    if (is.array(x) && !is.matrix(x)) "array",
    if (is.double(x)) "double",
    if (is.integer(x)) "integer",
    mode(x)
  )
}
iclass(matrix(1:5)) 
#> [1] "matrix"  "integer" "numeric"
iclass(array(1.5))
#> [1] "array"   "double"  "numeric"

Group 제너릭

  • Group 제너릭이라는 것도 있는데 상당히 advanced 된 내용이다.
  • 여러개의 제너릭들을 한데 모아, 다양한 클래스의 제너릭 메소드를 정의함
  • 예를 들어, abs, sign, sqrt 등의 제너릭은 Math라는 이름의 그룹 제너릭이다.

Exercises

  • Read the source code for t() and t.test() and confirm that t.test() is an S3 generic and not an S3 method. What happens if you create an object with class test and call t() with it
# t 는 원래 matrix 나 datafame 등을 받아, transpose 를 return 하는 함수이다. 
array(1:6, list(2,3))
#>      [,1] [,2] [,3]
#> [1,]    1    3    5
#> [2,]    2    4    6
t(array(1:6, list(2,3)))
#>      [,1] [,2]
#> [1,]    1    2
#> [2,]    3    4
#> [3,]    5    6
# t.test 는 제너릭이다.
a <- structure(c(1,2,3,4,5), class="test")

# 해당 코드는 one sample t-test 를 실행한다! 
# test 클래스를 보고, t.test 를 실행하기 때문 
# 이것은 t.test가 t 제너릭 메소드가 아니라 제너릭이기 때문이다. 
# 만약에 t.test가 t의 제너릭 메소드였다면, t(c(1,2,3,4,5)) 가 실행될 것이다. 
# 따라서 어떤 generic 을 생성할 때는 .을 포함하지 않도록 하는 것이 좋다. 
# t 를 실행하고 싶은데, t.test가 실행되는 등의 현상이 발생할 수 있다. 
t(a)
#> 
#>  One Sample t-test
#> 
#> data:  a
#> t = 4.2426, df = 4, p-value = 0.01324
#> alternative hypothesis: true mean is not equal to 0
#> 95 percent confidence interval:
#>  1.036757 4.963243
#> sample estimates:
#> mean of x 
#>         3
# 이런것도 가능하다. 
t.test <- function(a){
  print(a)
}
t(a)
#> [1] 1 2 3 4 5
#> attr(,"class")
#> [1] "test"
rm(t.test)
  • What classes have a method for the Math group generic in base R? Read the source code. How do the methods work?
  • abbc, sign, sqrt 등은 “Math” 그룹 제너릭이다.

Group “Math”:

abs, sign, sqrt, floor, ceiling, trunc, round, signif … 등등

methods(Math)
#> [1] Math,nonStructure-method Math,structure-method   
#> [3] Math.Date                Math.POSIXt             
#> [5] Math.data.frame          Math.difftime           
#> [7] Math.factor             
#> see '?methods' for accessing help and source code
  • R has two classes for representing date time data, POSIXct and POSIXlt, which both inherit from POSIXt. Which generics have different behaviours for the two classes? Which generics share the same behaviour?
methods(class="POSIXt") # 세 클래스에서 공통으로 정의된 제너릭 메소드
#>  [1] +            -            Axis         Math         Ops         
#>  [6] all.equal    as.character coerce       cut          diff        
#> [11] hist         initialize   is.numeric   julian       months      
#> [16] pretty       quantile     quarters     round        seq         
#> [21] show         slotsFromS3  str          trunc        weekdays    
#> see '?methods' for accessing help and source code
methods(class="POSIXct") # POSIXct 의 제너릭 메소드. 이 메소드는 POSIXt 에 추가하여 POSIXct 에서 새롭게 구현된 것이다.
#>  [1] Summary       [             [<-           [[            as.Date      
#>  [6] as.POSIXlt    as.data.frame as.list       c             coerce       
#> [11] format        initialize    length<-      mean          print        
#> [16] rep           show          slotsFromS3   split         summary      
#> [21] weighted.mean xtfrm        
#> see '?methods' for accessing help and source code
methods(class="POSIXlt") # POSIXlt 의 제너릭 메소드. 메 메소드는 마찬가지로 POSIXlt 에서 새롭게 구현된 것이다. 
#>  [1] Summary       [             [<-           [[            anyNA        
#>  [6] as.Date       as.POSIXct    as.data.frame as.double     as.list      
#> [11] as.matrix     c             coerce        duplicated    format       
#> [16] initialize    is.na         length        length<-      mean         
#> [21] names         names<-       print         rep           show         
#> [26] slotsFromS3   sort          summary       unique        weighted.mean
#> [31] xtfrm        
#> see '?methods' for accessing help and source code
  • Which base generic has the greatest number of defined methods?
library("methods") 
objs <- mget(ls("package:base"), inherits = TRUE)
funs <- Filter(is.function, objs) 
generics <- Filter(function(x) ("generic" %in% pryr::ftype(x)), funs)
  
sort(
  lengths(sapply(names(generics), function(x) methods(x), USE.NAMES = TRUE)),
  decreasing = TRUE
  )[1]
#> print 
#>   208
  • UseMethod() calls methods in a special way. Predict what the following code will return, then run it and read the help for UseMethod() to figure out what’s going on. Write down the rules in the simplest form possible.
y <- 1
g <- function(x) { 
  y <- 2
  UseMethod("g")
}
g.numeric <- function(x) y
g(10) # Internal variable 을 먼저 찾기 때문에 2가 된다.
#> [1] 2
#> [1] 2

h <- function(x) {
  x <- 10
  UseMethod("h")
}
h.character <- function(x) paste("char", x)
h.numeric <- function(x) paste("num", x)

h("a")
#> [1] "char a"
#> [1] "char a"
  • Internal generics don’t dispatch on the implicit class of base types. Carefully read ?“internal generic” to determine why the length of f and g is different in the example below. What function helps distinguish between the behaviour of f and g?
f <- function() 1 
g <- function() 2 
class(g) <- "function" 
class(f) 
#> [1] "function"
#> [1] "function"
class(g)
#> [1] "function"
#> [1] "function"

length.function <- function(x) "function" 

length(f)
#> [1] 1
#> [1] 1
length(g)
#> [1] "function"
#> [1] "function"

Answer : f는 implicit class 가 function 인 것이고, g 는 class=function 으로 정의된 것이다.

library(pryr)
# fytype 함수는 해당 function 이 internal/S3/S4/RC 인지를 알려준다. 
ftype(f) 
#> [1] "function"
ftype(g) 
#> [1] "function"
ftype(t.test) 
#> [1] "s3"      "generic"
ftype(length) 
#> [1] "primitive" "generic"
# 둘 다 function 으로 되는데 이것이 implicit class 인지는 아래처럼 확인할 수 있다. 
is.object(f) # f는 implicit class "function"" 이기 때문에 FALSE가 반환된다. 
#> [1] FALSE
is.object(g) # g는 s3 객체이기 때문에 TRUE 가 반환된다.
#> [1] TRUE