Project Euler Problem #1


1000보다 작은 자연수 중에서 3 또는 5의 배수를 모두 더하면?


10보다 작은 자연수 중에서 3 또는 5의 배수는 3, 5, 6, 9 이고, 이것을 모두 더하면 23입니다.

1000보다 작은 자연수 중에서 3 또는 5의 배수를 모두 더하면 얼마일까요?



Source Code (Github)



본 문항은 Project Euler 사이트에 영문으로 수록된 것을 한글로 변역한  Project Euler @ kr의 문항입니다. 

PyCharm을 활용한 파이썬 개발환경 구축

1. Python 다운로드 및 설치

- PyCharm IDE 설치에 앞서 파이썬을 먼저 설치해준다. Python 공식 다운로드 페이지에서 각자 머신에 맞는 릴리즈 및 버전으로 다운받아 설치한다.


2. PyCharm IDE 다운로드 및 설치

- 위에서 Python을 정상적으로 설치한 후에 JetBrain 홈페이지에서 PyCharm을 다운로드 받고 설치해주자. Community 버전이 무료로 제공되는 버전이다.


3. PyCharm 다운 및 설치

- PyCharm 설치가 완료 후, 실행해보자. 그러면 몇 가지 설정을 위한 선택사항이 나오는데 기본값으로 OK 또는 Accept을 눌러서 실행하자. 모든 설정을 마친 후 나오는 화면은 아래와 같다.

4. 프로젝트 생성 및 실행

- Python과 PyCharm이 설치되었다면, 간단한 프로젝트를 생성하고 실행함으로써 정상적으로 동작하는 지 확인하자. 아래는 간단한 'Hello World!'를 작성하고 실행시킨 결과화면이다.


IETF 미러포럼 기술 워크샵

IETF 기반 가상화 네트워크 및 응용기술



 08월 24일 수요일에 강남역에서 진행된 IETF 미러포럼 기술 워크샵이 시작되었다. 워크샵이 IETF 미러인만큼 최근 동향 및 제안되고 있는 블루프린트 및 새롭게 런칭되는 프로젝트에 대한 얘기가 주를 이뤘다. 특히, OPNFV와 관련하여 진행되는 프로젝트 및 주요 사항들에 대해서 조사 및 연구한 내용을 국내에 전파해주는 방식의 워크샵이었다. 1일차에는 숭실대, 고려대 교수 및 학생들이 발표를 진행했으며, 2일차에는 광주과학기술원 학생 역시 발표를 진행할 예정이다.


 첫 째날에 진행된 발표 내용 중에서 완벽히 이해되는 부분은 상당히 적었다. 커다란 컨셉들은 들어본 적은 있었지만 세부적으로 어떻게 디자인되고 있는지 모르는 내용이 대다수였기 때문에 이해하기 어려웠다. 해당 워크샵의 발표를 이해하기 위해서는 네트워크 동향 및 기술 변화에 대한 상당한 수준의 배경지식이 요구되었다. 그럼에도 불구하고 워크샵 참석에 의미가 있었던 부분은 새롭게 런칭하는 프로젝트가 무슨 일을 하는 것인지 일목요연하게 정리된 자료들을 볼 수 있었으며, 그간 무슨 그룹인지 몰랐던 OPNFV에 대해서 보다 자세하게 알 수 있었다는 점이다.


 OPNFV는 그간 NFV 사용 및 운용에 있어서 필요한 부분(Gap)을 확인하고, 해당 부분을 충족할 수 있는 방법에 대해서 프로포절 및 구현을 한 뒤 지속적으로 적용가능한 지 테스트 해주는 데에 비중이 크다. 아직 승인되지 않았지만 프로포절된 프로젝트까지 포함해서 약 50여개의 프로젝트가 운용될 예정이며, 모든 프로젝트가 어떻게 진행되는 지 쫒는 것은 불가능하다는 설명이다. 해당 워크샵에서도 많은 프로젝트 중에서 숭실대 연구실에서 주안점을 두고 보고 있는 다섯 개 정도의 프로젝트에 대해서 소개하는 자리를 가졌다.


 워크샵 발표 중 교수가 진행하는 내용은 상당히 트렌디하여 디테일하기보다는 전반적인 큰 그림을 설명하는 경우가 잦은 편이다. 따라서 상당한 배경지식이 있어야만 그 내용을 온전히 내 것으로 만들 수 있을 것 같다. 그러나 고려대 백상헌 교수님께서 진행하신 SFC에 대한 부분에서는 상당히 디테일한 디자인을 설명하고 있는 덕분에 듬성듬성일지라도 이해할 수 있었다. 그럼에도 크고, 작은 프로젝트에 대해서 디테일하게 설명하는 학생들의 발표 자료 및 내용이 쉽게 이해되는 편이다.


 전반적으로 온전하게 발표 내용을 내 지식으로 만드는 것에는 한계가 있었지만, 미려하게나마 네트워크 기술 트렌트의 냄새라도 쫒아가 본 경험을 할 수 있었다. 2일 차에서는 내가 앞으로 연구해야하는 OpenStack에 대한 발표를 연구실 선배들이 진행한다. 내일 오전이라도 집중해서 내 지식의 경계가 한 층 넓어지는 계기가 되길 희망한다.









Summer Workshop on Computer Communications

하계 컴퓨터통신 워크샵 2016



 올해 7월 초, 제주에서 진행한 KCC(Korea Computer Congress) 2016에 오픈소스 프로젝트인 I/O Visor를 토대로 논문을 작성해서 참석한 기록이 있다. 당시 제출했던 논문의 내용을 확장하고, 하나의 서비스로써 구축했던 내용에 대해서 논문으로 정리했고, 그 내용을 토대로 8월 말에 SWCC 2016 워크샵에 참석하게 되었다.

 당시 제출했던 논문의 제목은 리눅스 커널 네트워킹과 연계된 가상 스위치 플로우 모니터링의 실증 및 가시화로써 오픈소스 소프트웨어인 I/O Visor, InfluxDB 그리고 Grafana를 통해 네트워크 패킷을 캡쳐하고, 데이터베이스에 넣고, 사용자에게 유용하도록 시각화해주는 서비스를 정리한 내용이다. 개인적으로는 이번 논문에서 다루고 있는 애플리케이션은 혼자서 다양한 오픈소스 소프트웨어들의 핵심 기능을 엮어서 하나의 서비스를 구현했다는 점에서 의의가 있다고 생각한다. 논문에 대한 얘기는 여기까지 하고, SWCC 2016 참석한 후기를 남겨본다.

 워크샵 참석은 연구실에서 나와 교수님만 참석했다. 혼자서 학회를 간다는 것은 상당히 고려해야할 점이 많다는 것을 이번 기회에 새삼느끼게 되었다. 특히 장소가 강원도 홍천에 있는 오션월드였는데, 준성수기인 덕분에 숙박 가격이 너무 비싸서 차마 이용할 수 없었다. 학교측에서 지불해주는 숙박비에 두 배를 넘는 가격에서 맘 편히 잠들 기분은 아니었다. 혼자가 아니었더라면, 다같이 한 방에서 자고, 숙박비를 나눴더라면 이용해볼만 했겠으나 그럴 사람이 없다는 게 조금 섭섭하더라. 그리고 장소가 오션월드인만큼 주변을 돌아보면 워터파크에 놀러온 연인과 가족들로 바글바글했다. 이런 곳에 노트북과 발표자료를 들고 두리번 거리고 있는데 군중 속에 고독이 따로 없었다.

 장소에 대한 불만에 이어서 한 가지 더 불평, 불만을 늘어 놓자면 KCC 2016에 비해서 너무 학생 논문의 퀄리티나 발표자의 수준이 떨어진 것을 체감할 수 있었다. 발표에 대해서 준비를 안한 것도 확연히 보였고, 이들 사이에서 발표를 열심히 준비해야겠다는 생각을 유지하는 것은 쉬운 일이 아니었다. 전체 워크샵에 37편의 학생논문이 게재되었는데 너무나 대충 대충 넘어가는 발표 탓에 듣는 시간 조차 아까울 정도였다. 주최측의 진행조차도 매끄럽지 않았다. 애초에 공지로 내려왔던 17~20분의 발표시간은 당일 행사 지연으로 인해 10분 발표로 축소되었다. 준비조차 안하는 학생들과 이런 학생들을 배려(?)하는 듯한 발표 시간 축소는 너무나 실망스러운 조합이었다. 

 그래도 좋았던 점은 특별 세션의 내용이 상당히 유익했다는 점이다. 비록 수학에 약한 탓에 수식이 난무하는 슬라이드는 이해하기 어려웠지만, 그래도 맥락을 이해할 수 있었다. 상당히 언변이 좋은 교수님들이 많았고, 전달력이 좋았던 덕분에 모바일 클라우드, 머신러닝 등 익숙하지 않은 분야에 대한 정보를 얻을 수 있는 기회였다. 특히 첫 번째 발표였던 UNIST 김효일 교수님의 '모바일 클라우드 환경에서의 QoE 기반 Computation Offloading 기법' 발표와 둘 째 날 진행되었던 노영균 교수님과 이재성 교수님의 머신러닝/딥러닝에 대한 기초내용이 흥미로웠다.

 워크샵의 큰 파이를 차지하는 학생논문 및 발표에 대해서는 전반적으로 실망스러운 행사였지만, 특별 세션에서는 배울 점이 많은 유익한 시간이었다. 내년에는 이런 부분을 보완하여 보다 탄탄한 행사가 되기를 희망한다.





SWCC 2016 3단 리플렛.pdf


 이전에는 gcc 컴파일 시 발생하는 경고에 대해서는 무시했었다. 에러가 아닌이상 돌아가는 경우가 많았으니까. 그러나 이제는 그 원인 하나하나에 해결해서 깔끔하게 아무런 경고 메세지가 출력되지 않는 것을 추구하고 있다. 이런 이유에서 자주 무시하고, 해결 방법을 알아보지 않았던 경고 메세지 하나를 소개하고, 해결 방법을 적어본다.


unsigned int의 출력을 위한 포맷: %zu


 


 위 경고 메세지가 발생한 원인은 sizeof 함수에 있다. 소스코드를 굳이 포함시킬 필요가 없어서 배제했으나, 그 코드 내에서는 구조체를 선언하고, 그 구조체의 크기를 출력하기 위해 sizeof 함수를 사용했다. 사이즈를 %d 포맷으로 출력을 시도하는데, 이 때 경고 메세지가 발생한다. 이를 해결하기 위해서는 sizeof 연산의 출력을 위한 포맷으로 %zu를 사용하면 된다. 아래의 코드를 참조하자.


printf("size: %zu\n", sizeof(pos1));


 간혹 리눅스 터미널 환경에서 C언어로 코드를 작성하다보면, 뜻밖의 상황에서 에러를 맞이하게 된다. 비록 치명적이지 않고 간단한 에러임에도 불구하고, 매번 발생 원인을 잊고서 구글에 검색하는 경우가 잦은데, 이런 상황을 모면하고자 생기는 문제점을 기록하려한다. 간단한 문제인 만큼 추후에 기억하기 쉽고, 내 블로그를 참조할 누군가를 위해 간단하고 간략하게 작성할 참이다.



gcc 컴파일 시 <math.h> 헤더 파일 링크가 안 될 경우


 


 코드상에 별다른 문제가 없음에도 헤더파일 인식이 안되서, 위와 같은 에러가 발생하는 경우가 있다. 필자의 경우 <math.h>를 포함시켰는데도 불구하고 sqrt 함수가 정의되지 않았다고 나온다. 이는 <math.h> 헤더 파일에만 해당하는 경우는 아니므로, 정상적으로 코드 내 헤더 파일을 include 시켰음에도 특정 라이브러리 호출이 안된다면, 아래와 같은 명령어로 해결하자.


gcc -o "filename" "filename.c" -lm


 동일한 gcc 컴파일 명령어 뒤에 -lm을 추가함으로써 해결할 수 있다. gcc 컴파일러는 디폴트로 mathematical 라이브러리를 링크할 당시 포함시키지 않는다고 한다. 따라서 -lm 명령어를 통해 추가해줘야 한다.

 이번 포스팅은 C언어에서 자주 사용되는 문자열 관련 함수에 대해서 정리를 하려고 한다. Java 함수와는 다르게 유독 C언어 함수에 대해서는 자주 쓰는 것들도 암기가 잘 안되고, IDE를 통해 개발하기 보단 vim을 통해 작성하다보니 자꾸만 인터넷 검색을 하게된다. 물론 모르는 내용을 구글링을 통해 알아가는 것은 당연하지만, 반복적으로 같은 정보를 기억하지 않고 검색에만 의존하다보니 시간도 많이 잡아먹는 것 같아, 이 기회에 한 번 정리하고자 마음먹었다.



1. putchar, fputc, getchar, fgetc


 위 함수들 모두 문자열이 아닌 '문자'를 입력하고 출력하는 함수들이다. putchar와 fputc는 출력 스트림을 표준 출력으로 할 지, 아니면 사용자가 지정할 것인지의 차이를 보인다. 이 점과 마찬가지로 getchar와 fgetc의 차이 역시, 입력 스트림을 표준 입력으로 할 지, 사용자가 지정할 것인지의 차이가 있다. 특이점은 리턴 타입이 int이므로 이점을 기억하여 사용해야 한다. 그리고 getchar의 경우 버퍼에 남아있는 개행 문자를 처리할 때도 사용한다는 점을 기억하자. 


 해당 함수를 이용할 때 알아두어야 할 내용 중에 하나는 EOF에 관한 것이다. End of File의 약자로, 파일의 끝까지 와서 더이상 읽어들일 내용이 없다는 뜻이다. 키보드 입력의 경우 Ctrl+D, Ctrl+Z 입력이 EOF를 의미하게 된다. 실제로 위 두 함수에서 반환하는 EOF는 -1로 정의된 상수임을 잊지 말자.



2. puts, fputs, gets, fgets


 위 함수 중 문자열 입력 함수인 gets, fgets가 scanf 함수와 보이는 가장 큰 차이점은 공백이 있는 문자열을 입력받을 수 있다는 점이다. 더불어, puts, fputs의 차이 및 gets, fgets의 차이점은 위에서 언급한 입/출력 스트림을 지정할 것인가, 아니면 표준 입/출력 스트림을 사용할 것인가의 차이다. 추가적으로 puts 함수는 자동으로 개행을 진행하지만, fputs 함수는 자동 개행을 하지 않는다. gets 함수를 사용함에 있어서 미리 마련된 배열의 길이를 넘어서는 문자열이 입력되면, 할당되지 않은 메모리 영역을 침범할 수 있는 우려가 있다. 따라서 가급적이면 fgets 함수를 사용하는 것이 유익하다. 그러나 fgets 함수에도 주의해야 할 점이 있다. fgets 함수를 사용하면 특정 사이즈만큼 입력받을 수 있는데, 문제는 맨 마지막에 Null 문자를 포함하기 때문에 지정한 크기보다 하나 작은 길이만큼 읽어들인다. 또, fgets 함수는 개행 문자를 만날 때까지 문자열을 읽어들이는데, 개행문자까지 문자열에 포함시킨다.



3. fflush


 출력 버퍼를 비우는 함수. 출력 버퍼를 비운다는 것은 출력 버퍼에 저장된 데이터가 목적지로 전달되는 것을 의미한다. 그러나 입력 버퍼를 비운다는 것은 전혀 다른 내용이다. 입력 버퍼의 비움은 곧 데이터의 소멸을 의미한다. 특히 입/출력 동작중에 유독 엔터-키로 인해서 개행문자가 삽입되는 바람에 출력이 원하는 형태로 되지 않는 경우가 있는데, 위에 1번에서 언급했던 것과 같이 getchar 함수를 활용하면 이런 문제를 해결할 수 있다. 아래의 함수를 참조하자.


void EmptyOutputBuffer(void) {

while(getchar != '\n');

}



4. strlen


 문자열의 길이를 출력해주는 함수다. 반환형이 unsigned int를 대변하는 size_t 타입이라서 출력할 때 경고 메시지가 뜨는 경우가 다분하다. %d가 아닌, %zu 형식을 사용하면 해결된다. 뒤에 따라오는 개행문자를 제거하고, 순수하게 유효한 문자열만 입력받는데 사용되기도 한다. 아래의 함수를 참조하자.  strlen 함수를 이용하여, 문자열의 길이를 파악한 후 맨 마지막 문자열을 개행문자에서 Null로써 대체하고 있다.


void PureString(char str[]) {

int len = strlen(str);

str[len-1] = 0;

}



5. strcpy, strncpy


 문자열 복사에 사용되는 함수다. strncpy는 특정 길이를 명세하여, 명세된 길이까지 복사한다. 그러나 이 함수를 사용하기 위해서는 주의해야할 점이 있다. strncpy 함수는 딱 정해진 크기만큼 복사하는데, 그 안에 Null 문자를 포함하지 않을 수 있다. 따라서 출력 해보면 이상한 메모리 위치에 접근하여, 원하는 출력이 안될 수 있다. 따라서 해당 함수를 사용할 때는 아래 코드처럼 우회해서 사용하는 편이 안전하다. 아래처럼 문자열의 마지막 위치에 강제적으로 Null을 삽입될 수 있도록, 하나 작은 값까지 복사를 진행하자.


strncpy(str2, str1, sizeof(str2)-1);

str2[sizeof(str2)-1] = 0;



6. strcat, strncat


 문자열을 이어붙여주는 함수다. 기억할만한 점은 앞 문자열의 Null 문자 위치부터 덧붙여진다는 점이다. 따라서 사용자는 한 문자열에 두 개의 Null 문자가 생길 수 있는 가능성을 무시하고 사용할 수 있다. strncat의 경우, 덧붙일 문자열의 크기를 지정할 수 있는데, 해당 크기에는 Null 문자가 포함되어 있지 않다. 만약 10을 인수로 전달했다면, 10개의 문자열과 Null 문자열이 덧붙여져서 총 11개의 문자가 추가된다.



7. strcmp, strncmp


 두 문자열이 동일한 지, 아닌지를 판별할 때 사용한다. 같으면 0을 반환하고, 0이 아니면 다른 문자열이라고만 기억해도 충분할 것 같다. strncmp를 사용할 일은 거의 없을 것 같다. 



8. atoi, atof, atol


 문자열을 int, double, long으로 변환해주는 함수. 앞서 소개한 함수들은 <string.h>에 선언된 함수지만, 이 함수들은 <stdlib.h>에 선언되어 있다.



9. 마치며...


 위 함수들은 개발함에 있어서 정말 자주 사용되는 함수들이다. 반환형이나 인수 타입을 암기해서, 검색하는데 소모되는 시간을 절약하도록 하자. 특히 각 함수들이 가지고 있는 기본 기능외에 기억해야할 점이 있다. 대부분 개행문자와 관련된 점 또는 Null 문자와 관련된 점인데, 이런 부분을 정확하게 숙지해야만 문자열 입/출력을 다루는 데 문제 없이 능숙하게 처리할 수 있을 것 같다.



10. 참고


 열혈 C 프로그래밍 [윤성우 저]










 종강하면서 연구실에서 다루고 있는 연구 주제로 오픈소스 가상 스위치인 Open vSwitch의 내부 프로젝트인 OVN(Open vSwitch Virtual Network)에 대해 공부하게 되었다. OVN의 가장 대표적인 기능은 피지컬 머신들의 토폴로지의 상관없이 통신할 수 있도록 각 호스트간의 Overlay된 연결을 제공하는 것이다. 이런 기능을 제공하기 때문에, 기능 테스트를 위해서는 다수의 피지컬 머신을 갖춰야만 했고, 이 부분이 테스트하는데 귀찮고, 까다로운 부분이었다. 물론 연구실에 남는 데스크탑을 토대로 구축하면 됐을 일이지만, 연구실에서 보유 중인 데스크탑을 사용해봤으나 상태가 썩 좋지 않았다. 자연스레 VM 쪽으로 눈을 돌리게 됐다. VM을 사용한 테스트 환경 구축은 데스크탑을 일일히 가져와서 선을 꼽고, 준비하는 것에 비하면 너무 간편했다. 그러나 하이퍼바이저를 활용하여 로지컬한 머신을 생성하고, 생성한 머신에 OS를 설치하고, 다시 테스트에 필요한 소프트웨어를 설치하는 과정을 반복적으로 수행해야 한다는 점이 여전히 불편함으로 남았다. 그래서 이번에는 더욱 편하게 VM을 Provisioning 할 수 있는 방법에 대해서 알아보게 되었고, Vagrant를 알게되었다.


 아래는 Windows10 64bit 버전의 OS 환경에서 하이퍼바이저(VirtualBox)를 활용하여 Ubuntu-14.04.3 64bit 서버 VM 환경을 구축하는 내용을 다루고 있다.




1. Vagrant?


 Vagrant는 가상화 기술을 사용자로 하여금 쓰기 쉽고, 편하게 하여 개발 환경을 손쉽게 구축해주는 도구다. Vagrant를 활용하면 다양한 테스트 및 개발에 필요한 환경을 빠르게 구축할 수 있다는 점이 가장 큰 장점이다. 따라서 다양한 개발환경에서 기능 테스트를 수행하거나, 이전에 제작했던 시스템의 환경과 동일한 환경을 재현하는 데 사용될 수 있다. Opencloudengine의 Wiki에서는 다음과 같이 Vigrant의 이점을 설명하고 있으나, '빠르고, 간편한 VM Provisioning'으로 요약할 수 있겠다.

    • 과거 구축했던 개발 및 운영 환경을 즉시 재현할 수 있다.
    • 개발자가 만든 VM 이미지를 다른 개발자들과 공유할 수 있다.
    • VM 구성 및 배포를 커맨드 몇 번만으로 빠르게 진행할 수 있다.
    • 개발자가 구성한 VM을 서버에서도 그대로 사용할 수 있다.
    • VM 공유 기능을 제공한다.
    • 설치가 매우 쉽다.
    • 소프트웨어 구성 비용이 없다.
    • 유지보수 비용을 최소화할 수 있다.

 그러나 Vigrant는 오픈스택과 같은 Cloud IaaS를 구성하지 않는다. Network, Storage, Compute 가상화를 포함하는 가상화 기술을 제공하지는 않는다. 또한 그럴싸한 Web UI 제공이 안되며, VMware를 기반으로 사용하기 위해서는 유료 플러그-인을 구매해야하는 점이 있다.


2. Vagrant 사용과 Box에 대한 이해


 Vagrant 사용에 앞서 선행되어야 할 부분이 일부 있다. 먼저 하이퍼바이저 VirtualBox를 다운받아서 설치하도록 하자. 그 다음 마찬가지로 Vagrant 공식 페이지에서 제공하는 파일을 OS에 맞게 다운받아 설치하도록 한다. (필자는 Windows10 환경에서 진행했다.) 이렇게 두 개의 설치만 진행되면 사용을 위한 준비는 끝났다.


 이제 명령프롬프트를 켜서 아래의 두 명령어를 치면 VM이 자동적으로 설치된다. Vagrant 공식 페이지에서 제공하는 문서에서는 Root 디렉토리에 새로운 폴더를 만들어, 그 안에서 아래의 명령어를 수행하는 것을 권장하고 있다. 아래의 화면처럼 나온다면 설치가 정상적으로 진행된 것이다. 아마 대부분 눈치챌 수 있듯이, init 명령어 뒤에 들어가는 인수에 따라 어떤 버전의 OS로 설치할 지 결정한다. 각각의 OS를 담고 있는 이미지를 BOX라고 칭하는 데, 본 포스팅에서는 Ubuntu-12.04 64bit 버전인 precise64로 VM을 생성하고 있다.


vagrant init hashicorp/precise64

vagrant up




 앞서 말한 것과 마찬가지로 vagrant init 명령어는 뒤에 작성된 URL로부터 VM 세팅을 위한 템플릿을 가져온다. https://atlas.hashicorp.com/boxes/search에 접속해보면, vagrant에서 제공하고 있는 OS별, 구성요소별로 Box 설정을 위한 파일이 제공되고 있다. 이들 중 VM 환경으로 사용을 원하는 Box를 선택하고, init 명령어를 통해 해당 정보를 가져옴으로써 원하는 시스템 환경을 구축할 수 있다. 그리고 vagrant up 명령어를 통해 가져온 설정 정보를 토대로 VM을 생성해준다.


 아래의 화면을 보면 Virtual Box를 설치한 직후 아무것도 없는 상태에서 아래와 같이 하나의 로지컬 머신이 생성된 것을 확인할 수 있다.




 vagrant init 명령어를 치면, 해당 디렉토리에 'Vagrantfile' 파일이 생성된다. 이전에 Box가 VM 생성을 위한 템플릿이었다면, vagrantfile은 생성될 VM에 대한 세부 설정을 정의한다고 볼 수 있다. VM을 생성할 때, 어떤 box 파일을 사용할 것인지, VM에 할당할 CPU, Memory, Network 등의 configuration을 vagrantfile에서 정의 및 수정할 수 있다.



 'vagrant up' 명령어를 실행할 때 위와 같은 오류가 발생한다면 이는 Virtual Box 버전에 따른 오류다. 필자도 아래와 같은 오류를 해결하는데 시간을 꽤 많이 할애 했는데, 설정을 잘못 했다거나(사실 설정이라 할 것도 없지만..), 설치 과정에서 문제가 있었던 것은 아니었다. 단지 갱신된 Virtual Box 버전에 따라 동작하지 않았던 것이다. Vagrant 동작을 확인한 버전은 Virtualbox 5.0.24이므로 해당 버전으로 설치할 것을 권고하는 바이다.



3. VM Provisioning


 Vagrant를 사용하여 VM을 생성한다고 해도, 완벽한 Provisioning이 진행됐다고 보긴 어렵다. 각 VM에서 개발환경에 필요한 소프트웨어 설치가 수동으로 필요하다면, 이는 절반뿐인 Provisioning이다. 따라서 웹 서버, 미들웨어, DB등을 설치하고, Configuration 하기위한 방법이 필요하다. 물론 VM 생성을 위한 이미지 자체에 이들을 포함시켜서 배포하는 경우도 있지만, 이 경우 한 종류의 개발 환경만 배포되므로 유연한 사용은 어렵다.





 Vagrant는 이런 불편함을 해소할 수 있는 Provisioning 기능을 제공한다. VM 생성 후, vagrantfile에 기술된 provisioning script를 수행함으로써 필요한 소프트웨어를 자동으로 설치하고, configuration해준다. 위 사진처럼 Vagrantfile 작성 시, VM 시스템 환경을 구축하자마자 bootstrap.sh에 작성된 스크립트 언어에 맞춰 필요한 소프트웨어를 설치하고 설정해준다. 한 가지 주의할 점은 vagrantfile의 provisioning 부분에 기술된 명령어는 vagrant up, reload, provision 세 개의 멸령어가 실행될 때마다 매번 실행된다. 따라서 스크립트 내에 해당 소프트웨어가 설치되었는지 확인 후에, 설치가 안된 소프트웨어에 대해서만 설치를 진행하다록 스크립트를 작성하는 것이 좋다.



4. Vagrant를 활용한 다양한 개발환경 구축


 위에서 설명한 것과 마찬가지로 Vagrant를 활용하면 다양한 개발환경 구축이 간편하고 빠르게 가능하다. Vagrant 활용의 이해를 돕기 위해 아주 기본적인 환경 모델을 나열해봤다.

    • Ubuntu + Apache
    • Ubuntu + MySQL
    • Ubuntu + Tomcat
    • CentOS + Apache
    • CentOS + MySQL
    • CentOS + Tomcat

나열된 목록과 같이 box 및 vagrant provisioning 기능을 활용하여 서로 다른 형태의 VM을 빠르게 구축할 수 있다는 점이 바로 vagrant의 큰 매력과 장점이다.


5. 마치며...


 대학원에 진학 한 뒤로 반복적인 테스트는 일상이다. 반복속에서 특정 요인만 변경하면서 계속 실험결과를 추적해야하는 상황이 많다. 특히 우리 연구실의 경우에는 VM을 활용한 테스트 환경을 구축해야 하는 일이 잦은 편이다. 따라서 이번 기회에 배운 Vagrant를 활용하면, 앞으로 남은 대학원 생활 동안에 효율적으로 일을 할 수 있을 것 같다. 아직은 기본적인 사용에만 익숙하고, 나만을 위한 완벽한 Provisioning까지는 어려운 상황이다. Vagrant가 제공하는 Provisioning 기능을 활용하여 보다 디테일하고 타이트하게 구성되는 나만의 테스트환경 구축을 위해 조금 더 들여다봐야 할 것 같다.



6. 참고


https://www.virtualbox.org/wiki/Downloads

https://www.vagrantup.com/downloads.html

https://www.vagrantup.com/docs/getting-started/

http://wiki.opencloudengine.org/pages/viewpage.action?pageId=2852295

http://bcho.tistory.com/806




0. 개요


지난 시간에 다뤘던 [Python 강의] Dataset 조작하기 (1/2)에 이어서 이번에도 데이터-셋을 가지고 장난을 쳐보자. 이전에 사용했던 뉴욕시 택시정보에 대한 축약된 데이터-셋을 이용할 요량이니, 데이터를 삭제하거나 다운로드 받지 않았다면 링크된 이전 강의를 참고하면 되겠다.



1. 준비


일단 데이터를 만지작(?)하기 전에 필요한 라이브러리를 import하고, 데이터를 읽어서 변수에 할당해놓은 작업을 선행하자.



이번에도 마찬가지로 빠른 연산을 도와주는 numpy와 데이터 처리에 필요한 pandas, 그리고 가시적인 그래프로 데이터를 표현해줄 matplotlib를 import 시켰다. 또한 변수 data, fare에 각각 파일을 읽어서 할당해주었다. 현재 필요한 라이브러리는 모두 추가했다. 진행 중에 추가적으로 다른 라이브러리가 필요할 경우 그 때 삽입해줘도 괜찮으니 진행해보자.



2. 원하는 데이터만 뽑아서 보기


변수 data, fare에 저장된 데이터-셋은 꽤 크기가 크고 14개의 열을 가지고 있기 때문에 한 눈에 파악하기도 힘들 뿐더러, 필요없는 정보를 많이 포함하고 있다. 이번에는 택시를 이용한 승객이 이동한 거리 및 이동시간에 초점을 맞춰 데이터를 각색해보자.



데이터의 특정 열만 추려서 보고 싶다면 data[['trip_distance', 'trip_time_in_secs']]처럼 대괄호 안에 원하는 열의 이름을 기재하면 된다. 첫 번째로 승객의 이동 거리와 이동시간만 추려서 최초의 3개의 열을 보여주고 있다. 다음은 레코드의 정보를 자세히 보고 싶을 경우 loc 명령어를 통해 해당 레코드의 정보를 볼 수 있다. 자세히 살펴보면 data.loc[0]의 결과와 data.head(1)의 출력의 형태만 가로/세로로 다를 뿐이지 내용은 동일한 것을 알아챌 수 있다.



3. 인터렉티브하게 데이터 조작하기


이전 강의인 [Python 강의] Jupyter/IPython의 유용한 기능에서 다뤘던 Interactive Widgets를 이용하여 실시간으로 반영되도록 데이터를 조작할 수 있다. 앞서 import 했던 라이브러리와 별개로 새로운 라이브러리가 필요하므로 다시 import 해주자.



위에서 선언한 함수는 데이터-셋의 이동거리가 기준값(distance_threshold)보다 큰 레코드의 개수를 반환한다. 생성된 위젯을 마우스로 이리저리 옮겨보면, 그에 따라서 기준값이 변하고 덩달아 조건을 만족하는 레코드의 수가 변하는 것을 확인할 수 있다.



4. 새로운 열 추가 및 숫자 연산


데이터-셋에 기존에 없던 열을 새로이 추가할 수 있다. 또한 그 추가한 열에 기존의 데이터를 가공하여 채워줄 수 있는데 다음 코드를 보자.

data['trip_time_in_mins'] = data.trip_time_in_secs / 60.0


이 코드를 보면 'trip_time_in_mins'로 이동에 걸린 시간을 분 단위로 표현하는 열을 추가하고 있다. 이 열을 채워넣기 위해 기존에 있던 'trip_time_in_secs'를 60으로 나눗셈하고 있다. 아래의 화면은 전체 데이터 중에서 trip_time_in_secs, trip_time_in_mins만 추려서 최초 3개의 레코드만 출력하여 결과를 확인하고 있다.



또한 데이터를 열 단위 뿐만아니라 행 단위로도 추려서 볼 수 있다. 아래의 화면은 특정 열의 특정 행만 출력하고 있다. 즉 행과 열로 모두 축약되었다.



데이터-셋의 열 중에서 [이동 거리]열의 [0부터 5까지]의 행을 변수 a에 할당하고 있으며, [이동 거리]열의 [2부터 6까지]의 행을 변수 b에 할당하고 있다. 재밌는 점은 이렇게 추출한 데이터도 순서를 유지하고 있기 떄문에 덧셈(+) 연산의 결과 공통된 행끼리는 가능하지만 동일한 행이 아닐 경우에는 NaN(Not a Number)로 표기되는 것을 확인할 수 있다.



5. 각종 함수


이밖에도 데이터-셋을 조작하는데 기본적으로 제공되는 함수 몇 가지를 정리해보자. 우선 dayofweek는 datetime 형식의 데이터를 받아서 해당 날짜의 요일을 반환해준다. 변수 data에 할당된 데이터의 'pickup_datetime'열을 이용하여 승객이 탑승한 요일을 알아보면 다음과 같다.



[ : : 200000]으로 범위를 지정해줘서 200,000 번 간격으로 레코드를 출력하게 했다. 이렇게 처리하지 않으면 처음 데이터는 모두 결과가 1로 출력된다. (같은 날의 데이터들이 앞쪽에 몰려있기 때문이다.) 보면 0부터 6까지 총 7개의 숫자로 요일을 표기하고 있다.


다음은 'pickup_datetime'과 'dropoff_datetime'의 날짜만 비교(시간은 무시하고) 해보자. 이를 통해서 저녁 늦게 택시를 타서 다음 날이 되서야 내린 승객을 파악할 수 있다. 아니면 정말 택시를 오래타서 다음 날 하차한 승객일수도있다. 


코드의 아웃풋 최초 10개를 출력해보면 실제로 승차한 날은 1월 1일인데, 하차일은 모두 1월 2일임을 알 수 있다. 이처럼 기본적으로 제공하는 함수를 이용하면 기존의 데이터-셋을 가지고 다양한 정보를 추출해낼 수 있다.



6. 마치며...


[Python 강의] Dataset 조작하기 (1/2)에 이어서 두 번째로 데이터 처리에 관한 글을 게시했다. 이전에 글은 그래프를 그리면서 가시적으로 결과물을 보기에 흥미로웠던 부분이 있었다면, 이번 강의는 보다 실용적인 부분에 초점이 맞춰진 것 같다. 어떻게 생각하면, 데이터를 시각화하는 것은 데이터가 정립된 이후의 작업이기 때문에 이번 포스팅에서 다뤘던 내용을 선행한 후에 이전 강의를 다루는 편이 더 나을것 같다.







0. 준비


파이썬에서 기본적으로 데이터를 처리(읽거나 저장하거나 다른 형태로 재배열하는 등...)하는 프로세스는 대부분 Pandas를 이용한다. 쉽게 생각하면 Pandas로 읽어들인 데이터들을 빠르게 연산하기 위해 numpy를 사용한다고 보면 된다. 이번 시간에는 Pandas를 이용해서 '뉴욕시 택시'에 관련된 데이터-셋을 직접 다뤄볼 예정이다. 진행에 앞서 가볍게 데이터-셋를 다운받도록 하자. 실제적인 데이터는 17GB에 육박하지만 실습을 위해서는 테스트용으로 축소 제작된 80MB 정도의 작은 데이터-셋를 이용한다. 리눅스나 맥OS 환경에서 데이터-셋을 다운로드 하기위해서 명령어를 이용하면 되지만, 윈도우 환경에서는 불가하므로 웹 브라우저의 URL에 아래를 입력하도록 하자.

https://raw.githubusercontent.com/ipython-books/minibook-2nd-data/master/nyc_taxi.zip


다운로드가 완료되면 적당한 위치에 압축을 해제하고, 쥬피터 환경에서 새 파이썬 문서를 생성해주자.



1. Data read


먼저 데이터를 읽어오자. 데이터를 처리하기 위해서는 해당 데이터를 읽어서 변수에 저장하는 것이 선행되어야 한다. 데이터를 정상적으로 읽어오기 위해서는 자신이 압축을 해제했던 위치를 기억해두는 것이 좋다. 아래의 화면을 보면서 중요한 내용들을 짚어보자.



일단 기본적으로 numpy와 pandas를 사용하기 위해서 import 해주도록 하자. 또한 추후에 사용할 파이썬 내에서 그래프를 그려주기 위해서 matplotlib 역시 import 해주고, 문서 내에서 아웃풋을 확인하기 위해서 inline으로 설정해준다. 그리고 각각 변수 data_filename과 fare_filename에 읽어올 데이터의 위치를 입력하고, pandas에서제공하는 함수 read_csv를 통해 csv 문서를 data, fare 변수에 저장하도록 한다. 정상적으로 저장되었는지 확인을 위해서 data.head() 함수를 통해 처음 다섯 개의 레코드만 출력해보자.



2. 데이터 조작


조작이라고 하니 뭔가 부정적인 느낌이 들지만, 그냥 있는 데이터가지고 만지작해보자는 얘기다. 긍정적으로는 기존의 데이터를 토대로 의미있는 데이터를 추출해볼 수도 있다. 먼저, 변수 data에 저장된 데이터-셋의 열을 출력해보면 다음과 같은 열을 가지고 있는 것을 알 수 있다.



위의 열들을 각각 따로 저장하고, 일정 수식처리를 하는 함수를 제작했다. 함수 내부에 있는 연산은 [탑승 위치의 경도/위도]와 [하차 위치의 경도/위도]를 통해 이동한 거리를 계산한 것이 아닌가 예상해본다.



함수의 리턴값은 튜플인데 파이썬에서는 튜플을 한 번에 두 개의 변수에 할당할 수 있다. px, py에 동시에 할당한 후 정상적으로 할당되었는지 px를 출력해보자. 아래와 같은 화면이 나온다면 px에 데이터-셋의 일부가 제대로 할당되었음을 알 수 있다.




3. 데이터 시각화


pandas를 가지고 처리한 데이터를 그래프를 통해서 시각해보자. 이를 위해서 필요한 것이 위에서 import했던 matplotlib다. 일단 matplotlib가 제공하는 간단한 함수를 통해서 데이터-셋의 산포도를 확인해보자.

plt.scatter(px, py)



위에서 조작했던 데이터를 할당받은 px, py를 인수로 넣었더니 아래와 같은 산포도를 제공해준다. 왼쪽 상단의 점들이 집중된 점을 자세히 보기 위해서 아래의 조건으로 다시 산포도를 그려보자.



각 라인에서 크기, 점의 크기 및 투명도, 축의 이름, x축의 범위, y축의 범위, 축을 제거하고 있다. 이처럼 축소해서 보면 데이터가 나타내는 정보를 보다 명확하게 이해할 수 있다. 재미있는 점은 위의 그래프가 우리가 조작했던 데이터를 통해 얻은 산포도 그래프인데 이것이 뉴욕의 특정 지역의 지도와 유사한 것을 볼 수 있다.


위의 그래프와 구글 지도의 뉴욕시티를 비교해보면 가운데 분홍색으로 표시된 지역인 맨하튼에 지형과 거의 일치하는 것을 알 수 있다. 이를 통해서 대부분 택시 이용이 맨하튼에서 이뤄지는 것을 알 수 있는 것이다. 간단한 예지만 이처럼 데이터-셋을 통해서는 알 수 없었던 정보를 새롭게 추출할 수 있다는 점이 흥미롭다.


이밖에도 기본적인 함수를 통해서 데이터가 가지고 있는 특징들을 추려낼 수 있다. count, min, max, mean, median 등의 함수들은 전체 데이터-셋에서 레코드의 수, 최대/최소 등의 정보를 반환해준다. 이번에는 조작한 데이터를 토대로 히스토그램을 제작해보자. 먼저 보다 깔끔한 그래프를 그리기 위해서 seaborn을 설치하자. 설치하지 않아도 히스토그램을 출력할 수 있지만 설치하는 편이 가독성이 눈에 띄게 좋다.



seaborn 설치 후 아래의 명령어를 입력하면 px에 대한 히스토그램을 출력해준다. 필자는 이미 seaborn을 설치하고 import한 상태에서 진행해서 아래와 같은 그래프를 얻었다. seaborn을 import하기 이전에도 히스토그램은 생성이 가능하니, 보다 구린(?) 히스토그램을 이용하길 원한다면 seaborn을 이용하지 않으면 된다.

data.trip_distance.hist(bins=np.linspace(0., 10., 100))




4. 마치며...


pandas를 이용하여 csv 형식의 데이터를 읽어오고, numpy를 이용하여 데이터를 조작하고, matplotlib을 이용하여 조작된 데이터를 토대로 그래프를 생성했다. 또한 seaborn을 이용하여 생성한 데이터 그래프의 가독성을 높여줄 수 있었다. 이 모든 과정이 하나의 파이썬 문서 내에서 진행됐다는 점이 쥬피터 환경의 돋보이는 장점이자 흥미로운 점이다.