분류 전체보기 (336)

Tools/R

R - (3) 변수

2017. 2. 15. 01:38
반응형

https://www.tutorialspoint.com/r/r_variables.htm



변수


변수는 변수명을 통해 프로그램에서 데이터를 조작할 수 있도록 한다. 변수를 통하여 여러가지 자료구조를(atomic vector, vector, R-Object들의 여러가지 조합) 저장할 수 있다. 변수명에는 숫자, 문자, ., _가 포함될 수 있으며, 문자 또는 .을 첫글자로 하여야 한다. 단 .를 첫글자로 할 때는 .뒤에 숫자가 오면 안된다. 아래의 예를 참고하라.





변수 할당


# Assignment using equal operator.
var.1 = c(0,1,2,3)           

# Assignment using leftward operator.
var.2 <- c("learn","R")   

# Assignment using rightward operator.   
c(TRUE,1) -> var.3           

print(var.1)
cat ("var.1 is ", var.1 ,"\n")
cat ("var.2 is ", var.2 ,"\n")
cat ("var.3 is ", var.3 ,"\n")


변수할당은 = 또는 <-, -> 을 통해 할 수 있다. 또한 출력은 print(), cat()을 통해 할 수 있다. cat() 함수는 여러개의 인풋을 합쳐서 프린트한다.


결과


[1] 0 1 2 3
var.1 is  0 1 2 3 
var.2 is  learn R 
var.3 is  1 1 



변수들의 데이터 타입


R에서 변수의 데이터 타입은 변수에 할당되는 R-Object의 데이터 타입을 따른다. 그래서 R을 동적인 언어(dynamically typed language)라고 부른다. R에서는 변수의 데이터 타입이 하나에 고정되는 것이 아니라 계속해서 바꿀 수 있다. 


var_x <- "Hello"
cat("The class of var_x is ",class(var_x),"\n")

var_x <- 34.5
cat("  Now the class of var_x is ",class(var_x),"\n")

var_x <- 27L
cat("   Next the class of var_x becomes ",class(var_x),"\n")


The class of var_x is  character 
   Now the class of var_x is  numeric 
      Next the class of var_x becomes  integer



변수 찾기


현재 사용되고 있는 변수들의 목록을 보기 위해서는 ls() 함수를 이용한다. 또한 ls() 함수는 변수를 찾기 위해 '패턴'을 이용할 수도 있다. 


print(ls())


[1] "my var"     "my_new_var" "my_var"     "var.1"      
[5] "var.2"      "var.3"      "var.name"   "var_name2."
[9] "var_x"      "varname" 



# List the variables starting with the pattern "var".
print(ls(pattern = "var"))   


[1] "my var"     "my_new_var" "my_var"     "var.1"      
[5] "var.2"      "var.3"      "var.name"   "var_name2."
[9] "var_x"      "varname"  



주의할 점은 .으로 시작하는 변수들은 hidden 이다. 이것을 보기 위해서는 아래와 같이 all.name 파라미터를 TRUE로 설정한다.


print(ls(all.name = TRUE))



변수 삭제


변수는 rm() 함수를 사용해 지울 수 있다. 


rm(var.3)
print(var.3)


위의 스크립트를 실행시키면 var.3 변수를 삭제시키고 두 번째 줄에서는 에러가 뜬다.


rm(list = ls())
print(ls())


모든 변수를 지우고 싶으면 rm()과 ls()를 위와 같이 결합한다.



반응형

'Tools > R' 카테고리의 다른 글

R - (6) 반복문  (0) 2017.02.17
R - (5) If, else if, switch  (0) 2017.02.15
R - (4) 연산자  (0) 2017.02.15
R - (2) R의 데이터 타입 (자료구조)  (0) 2017.02.13
R - (1) Introduction  (0) 2017.02.13
반응형

https://www.tutorialspoint.com/r/r_data_types.htm


일반적인 프로그래밍에서는 값들을 저장하기 위하여 다양한 변수(Variables)들이 필요하다. 변수는 값을 저장한 메모리의 위치를 나타낸다. 이것은 변수를 만들면 그것이 메모리를 일정 공간을 차지한다는 것을 뜻한다. 문자, 정수, 실수, 진릿값 등 다양한 데이터를 변수에 저장하는 것이 필요할 것이다. 운영체제는 이러한 데이터 타입에 알맞게 변수에 메모리를 할당한다. 


R에서는 C나 Java와 같은 프로그래밍 언어와는 다르게 R 에서는 변수를 만들 때 데이터 타입을 선언하지 않는다. 변수는 R-Object로 할당되며 R-Object의 데이터타입이 변수의 데이터타입이 된다. 다양한 타입의 R-Object가 있지만 자주 사용되는 R-Object의 타입은 아래와 같다.



자주 사용하는 데이터 타입


  • Vectors
  • Lists
  • Matrices
  • Arrays
  • Factors
  • Data Frames

R-Object 중 가장 심플한 것은 vector object이고, 이 atomic vectors 또는 classes of vectors라고 불리는 것에는 아래와 같이 6개의 데이터 타입이 있다. 다른 R-Object들은 이 atomic vectors를 기반으로 한다.


  • Logical     
      • ex) TRUE, FALSE
  • Numeric
      • 12.3, 5, 999
  • Integer
      • 2L, 34L
  • Complex
      • 3+2i
  • Character
      • 'a', 'good'
  • Raw
      • "Hello" 는 48 64 6c 6c 6f로 저장된다.

atomic vectors

v <- TRUE 
print(class(v))

v <- 23.5
print(class(v))

v <- 2L
print(class(v))

v <- 2+5i
print(class(v))

v <- "TRUE"
print(class(v))

v <- charToRaw("Hello")
print(class(v))


결과 : 

[1] "logical"

[1] "numeric"
[1] "integer"
[1] "complex"
[1] "character"
[1] "raw"



Vectors

R 언어에서 가장 많이 사용되고 기본적인 R-Object는 Vectors이다. 이것은 위의 열거된 atomic vector들을 저장한다. Vectors는 c() 함수를 사용하여 만들 수 있다. 이것은 엘리먼트들을 벡터로 합친다는 뜻이다. (combine의 c)



# Create a vector.
apple <- c('red','green',"yellow")
print(apple)

# Get the class of the vector.
print(class(apple))



[1] "red"   "green" "1"    
[1] "character"




Matrices



매트릭스는 2차원의 데이터셋이다. 이것은 매트릭스 함수에 벡터를 제공함으로써 만들 수 있다.



# Create a matrix.
M = matrix( c('a','a','b','c','b','a'), nrow = 2, ncol = 3, byrow = TRUE)
print(M)
print(class(M))


     [,1] [,2] [,3]
[1,] "a"  "a"  "b" 
[2,] "c"  "b"  "a" 
[1] "matrix"


Arrays


매트릭스는 2차원에 한정되지만 arrays는 어떠한 차원으로 만들 수 있다.


# Create an array.

a <- array(c('green','yellow'),dim = c(3,3,2))

print(a)


, , 1

     [,1]     [,2]     [,3]    
[1,] "green"  "yellow" "green" 
[2,] "yellow" "green"  "yellow"
[3,] "green"  "yellow" "green" 

, , 2

     [,1]     [,2]     [,3]    
[1,] "yellow" "green"  "yellow"
[2,] "green"  "yellow" "green" 
[3,] "yellow" "green"  "yellow"


위 코드는 3차원의 array를 만들고, 원소들을 차례대로 green, yellow로 지정한다.


Factors


Factors는 vector로 만들어지는 R-object이다. Factors는 vector의 element들의 고유값(distinct value)를 레이블로 저장한다. 이 레이블들은 벡터 원소 타입이 어떻든 간에 항상 문자이다. Factors는 통계적 모델링에 유용하다. Factors는 factor()함수를 사용하여 만들 수 있다. nlevels() 함수를 통해 factors의 레벨을 알 수 있다.



# Create a vector.
apple_colors <- c('green','green','yellow','red','red','red','green')

# Create a factor object.
factor_apple <- factor(apple_colors)

# Print the factor.
print(factor_apple)
print(nlevels(factor_apple))

[1] green  green  yellow red    red    red    green 
Levels: green red yellow
[1] 3


Data Frames


데이터프레임은 구조화된 데이터 오브젝트이다. 매트릭스와 다른점은 데이터프레임은 컬럼으로 어떠한 데이터타입이든 넣을 수 있다. 첫 번째 컬럼은 numeric, 두 번째 컬럼은 문자열, 세 번째 컬럼은 논릿값 등 자유롭게 지정할 수 있다. 이것은 같은 길이의 vector들의 list로 볼 수 있다.


데이터 프레임은 data.frame() 함수를 통해 생성할 수 있다.


# Create the data frame.

BMI <-  data.frame(
   gender = c("Male", "Male","Female"), 
   height = c(152, 171.5, 165), 
   weight = c(81,93, 78),
   Age = c(42,38,26)
)
print(BMI)

gender height weight Age
1   Male  152.0     81  42
2   Male  171.5     93  38
3 Female  165.0     78  26



반응형

'Tools > R' 카테고리의 다른 글

R - (6) 반복문  (0) 2017.02.17
R - (5) If, else if, switch  (0) 2017.02.15
R - (4) 연산자  (0) 2017.02.15
R - (3) 변수  (0) 2017.02.15
R - (1) Introduction  (0) 2017.02.13
반응형

구글의 PaaS(Platform as a Service) 구글 앱 엔진(Google App Engine)에는 크게 두 가지 환경, standard environment와 flexible environment가 있습니다.


저 같은 경우 아무 생각도 없이 node.js google app engine 어플리케이션을 개발한 후 서버에 deploy 했는데, 지출 한도를 0으로 설정했음에도 불구하고 과금이 계속되어 결국에 25달러를 날리게 된 경험이 있습니다..


찾아보니 node.js의 경우 flexible 환경에서만 지원되고, 지출 한도는 standard environment에 적용되는 것이었습니다. 또한 flexible 환경에서는 cpu, memoery 등을 사용한 시간에 따라 과금되는 것이더라구요. 그래서 deploy가 된 시간만큼 요금이 나왔던 것이었습니다. 


아래는 두 가지 환경을 비교한 표입니다.


<https://cloud.google.com/appengine/docs/the-appengine-environments>








참고


https://cloud.google.com/appengine/docs/the-appengine-environments



반응형

Tools/R

R - (1) Introduction

2017. 2. 13. 01:06
반응형

원문 : https://www.tutorialspoint.com/r/index.htm


R tutorial


R은 통계 분석, 그래픽 표현 그리고 리포팅을 위한 프로그래밍 언어 및 소프트웨어 환경이다. R은 뉴질랜드 오클랜드 대학교의 Ross Ihaka and Robert Gentleman에 의해 만들어졌고, 현재는 R Development Core Team가 R을 개발하고 있다. R은 GNU(General Public License) 라이센스하에서 자유롭게 이용가능하며, 리눅스, 윈도우즈, 맥과 같은 다양한 운영체제에 컴파일된 바이너리를 제공하고 있다.  이 프로그래밍 언어 R은 두 명의 개발자, Ross Ihaka and Robert Gentleman 이름의 가장 앞 글자를 딴 것이다. 그리고 Bell Labs에서 만든 프로그래밍 언어 S를 근간으로한다.


대상 독자


이 튜토리얼은 R을 이용하여 통계 소프트웨어를 만들고자하는 소프트웨어 개발자, 통계학자, 데이터 마이너를 대상으로 한다. 만약 당신이 R에 처음이라면, 이 튜토리얼을 통해 R 언어의 대부분의 컨셉을 이해할 수 있고, 이를 통해 더 높은 레벨의 전문가가 될 수 있을 것이다.


선행 조건


이 튜토리얼을 시작하기 앞서 컴퓨터 프로그래밍 언어의 용어들에 대한 기본적인 이해가 필요하다. 프로그래밍 언어에 대한 기본적인 이해는 R 언어의 컨셉을 이해하고 학습하는데 도움이 될 것이다. 


반응형

'Tools > R' 카테고리의 다른 글

R - (6) 반복문  (0) 2017.02.17
R - (5) If, else if, switch  (0) 2017.02.15
R - (4) 연산자  (0) 2017.02.15
R - (3) 변수  (0) 2017.02.15
R - (2) R의 데이터 타입 (자료구조)  (0) 2017.02.13
반응형

Google App Engine + node js 환경의 sample 어플리케이션인 BookShelf 어플리케이션을 로컬에서 개발하려던 중,

npm start를 통해 어플리케이션을 실행한 후 홈에 접속하려고 할 때 아래와 같은 문제가 있었다.



Error: Could not load the default credentials. Browse to https://developers.google.com/accounts/docs/application-default-credentials for more information.



문제는 위의 에러 코드에서도 나오듯 아래 URL에서 확인할 수 있는데

https://developers.google.com/accounts/docs/application-default-credentials

Google App Engine 어플리케이션을 로컬에서 작동시키려면 Google App Engine API의 Credential이 필요하다. 


아래와 같은 방식으로 해결하였다. Google Cloud SDK가 설치된 상태에서 콘솔창에


gcloud auth application-default login


를 입력한다. 이후 웹 브라우저가 자동으로 실행되고 자신의 구글 계정으로 로그인하여 클릭을 하면 credential 파일이 로컬에 다운로드되고 알아서 그 파일을 어플리케이션 안에서 default credential로 잡게 되는 것 같다.


이후 다시 npm start를 통해 어플리케이션을 실행하면 Bookshelf 어플리케이션이 잘 구동되는 것을 확인할 수 있다.



반응형
반응형

이 책은 인종주의에 반대하는 책이다. 즉, 인종에 대한 선입견과 차별을 반대한다. '흑인은 지적으로 열등하다' 라거나, '아시아인은 소심하다' 와 같이 인종에 따라 사람을 평가해서는 안된다는 것이다. 이 책은 이와 같은 인종 차별적 연구 결과와 사람들의 선입견에 대해 유전체학으로 반론을 제기한다. (이 부분은 생물학적인 내용이 많이 들어가서 다소 어렵게 느껴졌다.) 이 책에 따르면 인종간의 차이를 정당화 할만한 유전적인 근거는 없다. 또한 만약 인종간에 유전적인 우열이 있다고 하더라도 이는 전체의 평균에 차이에 해당하는 것이므로 소속 공동체로 사람을 평가해서는 안되고 차별이나 계급을 정당화하여서는 안된다. 


이 책에서 저자의 결론은 아래와 같이 정리되었다.


  • 엄밀한 의미에서 인종은 생물학적 존재의의를 갖지 않는다.
  • 그렇지만 DNA를 통해 조상을 분류할 수는 있다.
  • 질병의 경우 인종에 따른 유전적인 영향이 있다. 하지만 그 탓을 100% 유전으로 돌리긴 어렵다.
  • '종'의 선천적 능력(흑인의 리듬감 등)은 과학적으로 증명하기 어렵다.


하지만 저자는 반인종주의도 반대한다. 왜냐하면 실제로 인종간에 드러나는 분명한 차이가 있기 때문일 것이다. 저자가 하고 싶은 말은 인종의 차이는 받아들이되, 그 차이를 평가해 증오와 대립의 동기로 삼지 말자는 것이다. 외면적으로 분명히 드러나는 차이를 외면한채 오로지 '다양성 존중' 이라는 명목하에 화합을 한다는 것은 위선이 아닐까. 오히려 그 차이를 분명히 인지한 채 포용하는 것이 진정한 화합이 아닐까 생각해 보았다. 

반응형
반응형

AOP란 무엇일까




저는 스프링을 공부하다 AOP를 처음 알게되었습니다.

AOP를 접하고 AOP가 도대체 뭔지, 어떻게 구현하는건지 궁금해서 몇 일 공부해봤습니다.

이 포스팅이 AOP가 무엇인지 궁금하신분들께 도움이 되었으면 좋겠습니다.



AOP의 정의


AOP는 한국에서 관점지향 프로그래밍, 또는 상황중심 프로그래밍으로 번역되는 하나의 프로그래밍 방법론입니다.

AOP는 절차지향이나 객체지향 프로그래밍처럼 그 자체로 하나의 프로그램을 형성할 수 있는 건 아닙니다.

하지만 AOP는 객체지향 코드 위에서 이루어지며 객체지향을 보조하는 역할을 한다고 보시면 됩니다.

 

 

AOP의 등장배경


AOP의 등장배경을 알기 위해 간단하게 프로그래밍 방법론의 발전과정을 말해보겠습니다.

처음 프로그래밍 언어가 생겨나고 프로그램이 생기기 시작했을 때 그 규모는 매우 작았습니다.

예를 들어 미사일의 사거리를 계산한다거나 식을 계산한다던가 하는 것이었습니다.

이 때의 프로그래밍 방식을 절차지향 프로그래밍이라고 합니다. 

절차지향은 매우 직관적입니다. 소스크드를 위에서 아래로 훑으면서 실행됩니다.

규모가 매우 작았기 때문에 프로그램을 효율적으로 작성하는 방식의 필요성이 제기되지 않았습니다.

 

하지만 프로그램을 일반 기업에서 사용하게 되면서 점점 프로그램의 규모가 커지기 시작합니다.

그러자 소프트웨어 개발 시장은 위기에 처합니다. 절차지향 방식은 큰 프로그램을 만드는데 매우 비효율적이었습니다.

이제 소프트웨어 시장에서는 거대한 프로그램을 개발하고 유지보수하기 위한 새로운 방법론이 필요했습니다.

이 때 등장한 것이 객체지향프로그래밍(OOP : Object Oriendted Programmin)입니다.

 

OOP는 객체(Object)라는 혁신적인 개념을 활용함으로써 큰 프로그램을 모듈단위로 축소시켜

작성할 수 있게 함으로써 이 위기를 극복합니다.

 

하지만 이러한 객체지향방식에도 허점이 있었습니다.

객체지향 방식의 장점중의 하나는 프로그램을 모듈화 시켜 이를 재활용함으로써 

코드의 중복을 줄이고 코드의 재사용성을 높이는 것입니다.

 

하지만 프로그램의 크기가 엄청나게 커지면서 이러한 모듈 안에서마저 중복되는 코드가 생기게 되는 것이었습니다.

이를 횡단 관심사(Crosscutting-Concerns)라고 합니다. 그 중 자주 언급되는 것이 바로 트랜잭션, 로깅, 성능 분석 등입니다.

이러한 횡단 관심사들은 여러 모듈들을 말 그래도 횡단하면서 존재하게됩니다.

횡단 관심사는 AOP를 이해함에 있어서 매우 중요한 개념입니다. 포스트 맨 위 사진이 바로 AOP의 개념도입니다.

 

AOP의 목적은 바로 이러한 횡단관심사를 모듈화 하는 방법을 제시하는 것입니다.

이를 통해 코드의 중복을 제거하고 이해하기 쉽게하게 프로그램의 작성을 쉽게하고 유지보수를 편리하게 할 수 있습니다.

 

 

AOP의 구현


AOP의 구현하는 방법에는 여러가지가 있습니다.

스프링 AOP에서는 애노태이션과 xml을 활용하여 보통 소스에서는 보이지 않게합니다.

하지만 지금은 AOP가 무엇인지 이해하는게 목적이므로 친숙한 자바 코드로 설명해보겠습니다.

아래의 Java 코드를 봅시다. 


public class BoardService {
 public void addArticle(BoardBean board){
  try {
   boardDao.add(board); // 비지니스 로직
   memberDao.levelUp(board.userId);
   this.transactionManager.commit(); // 커밋
  }
  catch(Exception e){
   this.transactionManager.rollback(); // 롤백
  }
 }
}


위의 BoardService 클래스의 addArticle 메소드를 보면 boardDao.add(board), memberDao.levelUp(board.userId)라는 비지니스 로직과 트랜잭션에 관련된 코드가 섞여 있음을 볼 수 있습니다. 사실 대부분의 프로그래머들은 소스를 위처럼 짤 것입니다. 위 처럼 짜도 그렇게 잘못된 코드는 아닌 것 같습니다. 하지만 트랜잭션을 적용하는 메소드들이 많아지면 많아질 수록 트랜잭션 관리 코드가 늘어나게 되고 이를 일괄적으로 관리하게 어려워지는 것이 사실입니다.

 

위 코드를 이처럼 바꿔봅시다.


class BoardServiceTx implements BoardService {
 BoardService boardService = new BoardServiceImpl();
 public void addArticle(BoardBean board){
  try {
   boardService.addArticle(board); // 위임
   this.transactionManager.commit();
  }
  catch(Exception e){
   this.transactionManager.rollback();
  }
 }
}
 
class BoardServiceImpl implements BoardService {
 public void addArticle(BoardBean board){
  try {
   boardDao.addArticle(board);
   memberDao.levelUp(board.userId);
  }
 }
}


BoardServiceTx 는 트랜잭션을 구현하는 코드이고 BoardServiceImpl은 비지니스 로직을 구현하는 코드입니다.

BoardServiceTx 는 비지니스로직을 BoardServiceImpl 에게 위임하고 있습니다.

 

하나의 클래스를 둘로 분리하면서 트랜잭션과 비지니스 로직을 분리하는데 성공했습니다.

하지만 메소드들이 더 많아지면 try catch 문은 계속해서 쓰이게 됩니다.

트랜잭션과 비지니스 로직 두 개의 관심사를 분리하였지만 중복을 제거하지는 못한 것입니다.

 

이제 우리의 목적은 트랜잭션 코드를 딱 한 번만 쓰는 것입니다.

저 try catch 문을 한 번만 쓰게 되면 작성할 코드의 양을 현저하게 줄일 수 있고 관리하기도 편해질 것입니다.

이것을 위해서는 자바의 리플렉션에 대해서 먼저 알아야합니다.

 

public static void main(String[] args){
 String name = "AOP";
 Method lengthMethod = String.class.getMethod("length");
 int length = lengthMethod.invoke(name);
}


위 코드에서 length에는 3이 저장됩니다. String 클래스의 length 메소드를 Method라는 객체에 저장시키고

이를 invoke라는 메소드를 통해서 실행시킬 수 있습니다!

이러한 invoke라는 개념을 활용한게 자바의 InvocationHandler 인터페이스와 Proxy객체입니다.  

아래는 InvocationHandler를 구현하는 TransactionHandler 클래스입니다.



public class TransactionHandler implements InvocationHandler {
 private Object target;
 private PlatformTransactionManager transactionManager;
 private String pattern;
 
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
  invokeInTransaction(method, args);
 }
 
 private Object invokeInTransaction(Method method, Object[] args) throws Throwable {
  TransactionStatus status = this.transactionManager.getTransaction
    (new DefaultTransactionDefinition());
  try {
   Object ret = method.invoke(target, args);
   this.transactionManager.commit();
   return ret;
  }
  catch {
   return method.invoke(target, args);
  }
 }
} 


위의 TransactionHandler는 InvocationHandler를 구현하고 있습니다.

이렇게 한 후에 아래처럼 Proxy.newProxyInstance의 3번째 인자로

TransactionHandler의 인스턴스인 txHandler를 넣어주면 boardService의 모든 메소드를 실행할 때

TransactionHandler의 invoke 메소드를 실행하게 됩니다.

신기하지 않으신가요? 자바 API로 가능한 것들입니다. 지금은 저 복잡한 문법에는 신경 쓰지 않으셔도 됩니다.

AOP를 이해하는게 이 포스팅의 목적이니까요..


class BoardController {
 TransactionHandler txHandler new TransactionHandler();
 txHandler.setTarget(new BoardServiceImpl());
 txHandler.setTransactionManager(transactionManager);
 BoardService boardService = (BoardService)Proxy.newProxyInstance(
   getClass().getClassLoader(),
   new Class[] {BoardService.class},
   txHandler);
   
   public void addArticle(BoardBean board){
    boardDao.addArticle(article);
    memberDao.levelUp(board.userId)
   }
}



위의 BoardController 코드는 실제로 AOP를 사용하는 코드입니다. (메인함수라고 보시면됩니다.)

사용자가 글을 쓸 때 addArticle이라는 메소드가 호출될 것입니다.

addArticle 메소드에는 트랜잭션이 적용되었지만 트랜잭션에 관한 코드는 보이지 않습니다.

이렇게 boardService에 Handler를 적용시킴으로써 비지니스 로직과 트랜잭션이라는 두 개의 관심사가 분리되었고

트랜잭션에 관련된 코드를 한 곳으로 모아 작성할 코드의 양을 줄이고 관리하기도 편하게 되었습니다.

이로써 AOP의 목적에 부합하는 코드를 실제로 구현해 보았습니다.

 

물론 이게 AOP의 끝은 아닙니다. 맛보기라고 보시면 됩니다. 실무에서는 여러가지 애노테이션과 xml을 활용하기 때문에 AOP를 제대로 활용하고 싶으시다면 AspectJ 또는 Spring AOP를 학습하시면 좋습니다.

반응형
반응형

/**

2017.02.02 작성자 : 3개월

Tensorflow - MNIST 단일 계층 신경망 트레이닝

*/


환경 : windows tensorflow, anaconda 4.3, python 3.5



Tensorflow를 통해 단일 계층 신경망을 구축하고 MNIST 데이터를 training하고 test 하는 예제입니다. 많은 예제들이 tensorflow 내부에 example로 있는 MNIST 데이터를 이용하지만 이 포스팅에서는 외부에 있는 MNIST pickle 파일을 다운로드하고 이를 읽어들여 모델을 구축해보았습니다. 사용한 MNIST pickle 파일은 https:na//github.com/mnielsen/neural-networks-and-deep-learning/blob/master/data/mnist.pkl.gz 이곳에서 다운로드 받을 수 있습니다. 


1. 데이터 읽기


import tensorflow as tf
import gzip, numpy
import pickle as cPickle
import pandas as pd

# Load the dataset
f = open('data/mnist.pkl', 'rb')
train_set, valid_set, test_set = cPickle.load(f, encoding='latin1')
f.close()

x_train, y_train = train_set
x_test, y_test = test_set


pickle로 불러온 변수에는 train_set, valid_set, test_set이 나뉘어져 있기 때문에 위와 같이 load하면 알아서 training, validation, test set으로 나눌 수 있습니다. 또한 각각은 튜플 자료구조형으로 또 다시 x, y로 나뉘어져 있기 때문에 x_train, y_train = train_set 구문을 통해 feature과 label을 분리할 수 있습니다. 이렇게 데이터를 빠르게 training을 적용할 수 있는 형태로 만들어낼 수 있다는 것이 pickle 파일의 좋은 점입니다. 하지만 예제가 아닌 실제 머신러닝 모델을 구축할 때는 이러한 과정을 모두 직접하여야 합니다. 이미지 파일을 읽어들여야하고 또 이것을 적절한 사이즈의 numpy array로 바꾸어야합니다. 


2. 데이터 전처리


y_train = pd.get_dummies(y_train)
y_test = pd.get_dummies(y_test)


label들을 one hot encoding합니다. tensorflow에서는 label을 one hot encoding 하여 제공하여야 합니다.


print('x_train shape : ',x_train.shape) # (50000, 784)
print('y_train shape : ',y_train.shape) # (50000, 10)
print('x_test shape : ',x_test.shape) # (10000, 784)
print('y_test shape : ',y_test.shape) # (10000, 10)


training data와 test data의 형태(shape)를 프린트하여 보겠습니다. MNIST 데이터는 28*28 흑백 이미지이므로 총 784개의 픽셀이 있는데 이를 feature로 보아 784개의 feature가 있음을 알 수 있습니다. 


[mnist 데이터 모양]



또한 training data의 갯수는 50000개이기 때문에 x_train의 모양은 50000*784 입니다. label의 갯수도 50000개이며 class의 갯수가 0~9까지 10개이므로 y_train은 50000*10입니다. 만약 label이 1인 경우 y는 [0 1 0 0 0 0 0 0 0 0 0] 으로 encoding 됩니다. y_train에는 이러한 y가 50000개 있다고 생각하면 됩니다.


3. 모델 작성


x = tf.placeholder('float', [None, 784]) W = tf.Variable(tf.zeros([784,10])) b = tf.Variable(tf.zeros([10])) y = tf.nn.softmax(tf.matmul(x, W) + b) y_ = tf.placeholder('float', [None, 10]) cross_entropy = -tf.reduce_sum(y_*tf.log(y)) train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)


윗 부분은 데이터를 읽어들이고 numpy와 pandas를 이용하여 데이터를 전처리 한 것이었다면 이제부터는 본격적으로 tensorflow 코드를 작성하여 보겠습니다.


x = tf.placeholder('float', [None, 784])


우선 placeholder을 이용해 x가 들어갈 공간을 만들어줍니다. 이 때 [None, 784]에서 None은 데이터의 갯수는 자유롭게 설정하겠다는 뜻입니다. 하지만 feature의 갯수 784는 고정되어 있습니다. 


W = tf.Variable(tf.zeros([784,10]))


그 다음 weight matrix를 만드는데 input layer의 노드가 784개이고 output layer의 노드가 10개이므로 총 784*10개의 weights가 필요한 것을 알 수 있습니다. 이를 위해 W라는 tensorflow 변수를 만들고 0으로 초기화 시킵니다. 


b = tf.Variable(tf.zeros([10]))


bias는 output layer의 node수만큼 필요하므로 10개를 만들고 0으로 초기화 시킵니다.


y = tf.nn.softmax(tf.matmul(x, W) + b)


그 다음 x와 W를 매트릭스 곱셈을 하고 bias를 더한 것에 softmax 함수를 취하여 이를 y 변수로 만들어줍니다. 수식으로 표현하면  y = softmax(xW+b) 이 됩니다. 이 때 y는 '예측값' 입니다.


cross_entropy = -tf.reduce_sum(y_*tf.log(y)) train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)


손실 함수로는 classification의 경우 크로스 엔트로피를 사용하게 됩니다. -y_*log(y) 에는 데이터들의 크로스 엔트로피들의 2차원 텐서가 담겨져 있습니다. reduce_sum 함수를 통해 이 크로스 엔트로피들의 평균을 구합니다. 이 때 reduce_sum 함수는 지정된 차원을 따라 평균을 내는 것입니다. 2차원인 경우 지정할 차원이 1개 밖에 없으므로 차원을 따로 지정한 필요가 없습니다. 그래서 이 경우에는 reduce_sum 함수는 평균을 구한다고 생각하시면 됩니다.



4. 배치 트레이닝


sess = tf.Session()
sess.run(tf.global_variables_initializer())

batch_size = 100 # 배치 사이즈 지정
training_epochs = 3 # epoch 횟수 지정

# epoch 횟수만큼 반복
for epoch in range(training_epochs) :
    batch_count = int(x_train.shape[0]/100) # 배치의 갯수
    for i in range(batch_count) : # 배치를 순차적으로 읽는 루프
        # 배치사이즈 만큼 데이터를 읽어옴
        batch_xs, batch_ys = x_train[i*batch_size:i*batch_size+batch_size], y_train[i*batch_size:i*batch_size+batch_size] 
        
        # training, 이를 통해 W, b Variable 값을 조정함
        sess.run(train_step, feed_dict = {x : batch_xs, y_ : batch_ys})
        
        # [True False True False False True True ....] 와 같은 boolean vector
        correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
        
        # [1 0 1 0 0 1 1 ...]로 변환 후 평균값을 구하면 accuracy 구할 수 있음
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
        
        # 5번 배치를 읽고 이를 트레이닝한 후 정확도 출력
        if i % 5 == 0 : 
            print(str(epoch+1)+' epoch '+ str(i)+' batch ', sess.run(accuracy, feed_dict={x: x_test[0:100], y_: y_test[0:100]}))


이 부분을 이해하기 위해서는 우선 배치 트레이닝에 대하여 알아야 합니다. 배치 트레이닝이란 트레이닝 데이터를 일정 사이즈로 쪼갠 미니 배치(mini batch)를 통해 Gradient Descent를 하는 방법입니다. 일반적인 Gradient Descent 방법은 전체 트레이닝 데이터를 한 번 쭉 보고 gradient를 구한 후 weights와 bias를 '한 번' 업데이트 시킵니다. 하지만 이런 방법은 computation cost가 높습니다. 하지만 미니 배치를 이용한 방법은 전체 데이터의 샘플인 미니 배치를 통해 전체 데이터를 근사 시킵니다. 그리고 이것만 보고 gradient를 구한 후 weight, bias를 업데이트 시킵니다. 예를 들어 배치 사이즈가 128이면 128개의 데이터 샘플들만 보고 gradient를 구한 후 weight, bias를 업데이트 하게 됩니다. 이전 방식에 비해 훨씬 빠르게 weight를 업데이트 시킬 수 있죠. 이렇게 weight를 구하는 방식은 Stochastic Gradient Descent 방법이라고 부릅니다. 실제로 일반적인 Gradient Descent 방법보다는 Stochastic Gradient Descent 방법이 더 많이 쓰입니다. 팁으로는 배치 사이즈는 메모리가 허용하는 범위 내에서 최대한 크게 잡는 것이 좋습니다. 그리고 보통 배치사이즈는 128, 256, 512와 같이 2의 배수로 잡는 경우가 많은데 혹자는 이를 CPU 연산의 효율을 증가시킨다고 합니다. 하지만 111, 234와 같이 아무 배치 사이즈나 잡아도 트레이닝은 잘 합니다.


이러한 배치 트레이닝의 방식을 이해한다면 위의 텐서플로우 코드도 어렵지 않게 이해할 수 있습니다. 


sess = tf.Session()
sess.run(tf.global_variables_initializer())

세션을 만들고 variable을 초기화 시킵니다. 

  • 텐서플로우에서 Variable은 반드시 위와 같이 초기화 시키고 이용해야합니다.

batch_size = 100 # 배치 사이즈 지정
training_epochs = 3 # epoch 횟수 지정


배치 사이즈와 epoch를 정합니다. epoch은 '전체 데이터를 보는 횟수' 입니다.


# epoch 횟수만큼 반복 for epoch in range(training_epochs) : batch_count = int(x_train.shape[0]/100) # 배치의 갯수 for i in range(batch_count) : # 배치를 순차적으로 읽는 루프 # 배치사이즈 만큼 데이터를 읽어옴 batch_xs, batch_ys = x_train[i*batch_size:i*batch_size+batch_size], y_train[i*batch_size:i*batch_size+batch_size] # training, 이를 통해 W, b Variable 값을 조정함 sess.run(train_step, feed_dict = {x : batch_xs, y_ : batch_ys}) # [True False True False False True True ....] 와 같은 boolean vector correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1)) # [1 0 1 0 0 1 1 ...]로 변환 후 평균값을 구하면 accuracy 구할 수 있음 accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float")) # 5번 배치를 읽고 이를 트레이닝한 후 정확도 출력 if i % 5 == 0 : print(str(epoch+1)+' epoch '+ str(i)+' batch ', sess.run(accuracy, feed_dict={x: x_test[0:100], y_: y_test[0:100]}))


이제 마지막 트레이닝 파트입니다. 미니 배치를 구할 때 전체 데이터에서 샘플 데이터를 랜덤으로 뽑는 방식도 있지만 여기서는 그냥 순차적으로 배치를 만들었습니다. 0번부터 100번까지를 1배치, 101번부터 200번까지를 2배치와 같은 방식으로 말입니다. (사실 데이터의 순서에 어떠한 규칙이 있다면 이러한 방식은 좋지 않을 수 있습니다.) epoch만큼 전체 데이터를 보아아햐고 또 배치 사이즈만큼 전체 데이터를 쪼개야하니까 이중 for문을 써야하는 것을 알 수 있습니다. 그리고 두 번째 for문에서는 i라는 인덱스와 batch_size라는 변수를 이용하여 원하는 만큼 데이터를 계속해서 불러온후 Gradient Descent를 하면됩니다. 각각의 문장이 의미하는바는 코드에 주석으로 써두었습니다. 


5. 결과



 배치 트레이닝을 100번 했을 때 이미 정확도가 0.93에 육박하는 것을 알 수 있습니다.




트레이닝이 끝났을 때의 최종 정확도는 0.96 이었습니다. 이미 100번 트레이닝을 했을 때 정확도가 0.93이었기 때문에 그 이상의 training은 의미가 없었을지도 모릅니다. 지금은 validation과정 없이 마구잡이로 트레이닝을 했지만 보통은 언제 training을 끝내야하는지 잘 선택하여야합니다. 계속되는 불필요한 training은 overfitting을 유발할 수 있기 때문입니다. 


반응형
반응형

4p Medicine(4p 의학)은 2000년대 중반에 제안된 것으로 p로 시작하는 4가지 의료 혁신의 목표 예방의료(preventive medicine), 맞춤의료(personalized medicine), 참여의료(participatory medicine), 예측의료(predictive medicine)를 의미하는 약자입니다. 막연한 구호처럼 여겨지던 4p medicine이 최근 디지털 의료, 빅데이터 기술, 유전체 기술의 발달로 인해 차근차근 구현 되어 나가고 있습니다. 


  • Preventive Medicine(예방의료) : preventive medicine은 질병의 치료(disease treatment)와 반대되는 개념으로 질병이 일어나기 전에 미리 방지하는 방법입니다. 질병은 유전적 요인이나 환경적 요인에 영향을 받기 때문에 이것들을 분석함으로써 질병이 발생하기 전에 미리 질병 발생의 확률을 예측할 수 있고 이를 방지할 수 있습니다. 

  • Personalized Medicine(맞춤의료) :  personalized medicine이란 어떠한 개인을 약물에 대한 반응, 질병 위험도 등을 통해 분류하고 이를 통해 개인에 맞춘 의학적인 결정을 내리거나 약을 처방하는 등을 하는 의학적인 절차입니다. 

  • Participatory Medicine(참여의료) : participatory medicine은 환자가 의사와 함께 의학적인 결정에 참여하는 것입니다. 최근 다양한 health care 앱들이 등장함으로써 개인이 의사에 의존하는 정도가 점점 줄고 있습니다.

  • Predictive Medicine(예측의료) : predictive medicine은 질병의 발생 확률을 예측하고, 이를 통해 질병을 방지하거나, 질병이 환자에게 미칠 영향을 유의하게 줄이는 것을 수반합니다. genomics(유전체학), proteomics(단백질체학), cytomics 등 다양한 예측의 방법론이 있는데 가장 기본적인 방법은 유전학으로 미래의 질병을 예측하는 것입니다.

* Personalized Medicine은 Precision Medicine이라고도 불립니다. 


아래는 4p medicine에 대해 이해하기 위해 스크랩한 자료들입니다. 




출처 - https://www.esprevmed.org/news/video-explaining-p4-medicine-preventive-predictive-personalized-participatory/


출처 - http://www.yoonsupchoi.com/2016/02/28/digital-medicine-1/

반응형
반응형

문제

ImportError: No module named cv2


해결


파이썬 opencv 가 설치되어있지 않아서 생기는 문제로 이를 해결하기 위해 conda install opencv, pip install opencv 등을 해보았지만 제대로 되지 않았습니다. 그래서 opencv 홈페이지에서 직접 윈도우즈용 opencv를 설치하였고 설치된 폴더, opencv\build\python\2.7\x64 이곳에서 파이썬 모듈 cv2.pyd를 Anaconda2\Lib\site-packages에 복사하였더니 문제가 해결되었습니다. 

 

http://speark.tistory.com/9


위 블로그를 참고하였습니다.

반응형