저번 편에 이어서 같은 데이터를 가지고 빅데이터 분석 툴인 Spotfire로 데이터 분석을 시도해 보겠다.


Spotfire 란 ? 

mySQL, msSQL과 같은 기능을 하는 데이터 분석 도구 중의 하나로, 무료 다운로드 판에서 더욱 손쉽게 데이터를 돌리며 분석할 수 있다. 



Excel로 얻어낸 패턴을 Spotfire로 불러와서 Day 1~5까지의 유저 접속 시간 패턴을 분석하였다. 방법은 아래에 내가 작성한 ppt에 자세하게 나와있다 ! 




▶ 위와 같이 비슷한 기울기를 가진 다섯 개의 그래프를 얻을 수 있다. 그런데 2일차 이후에는 이탈 기울기가 완만한 것을 확인 가능하다. 여기서 1일차 당일에 게임 지속 여부가 결정난다는 것을 예측할 수 있다.




▶ 또한 그래프 상에서 최고 꼭짓점을 확인했을 때, 주로 20 - 22시 사이를 가리키는 것을 알 수 있다. 이로써 peak time이 20 - 22시 사이라는 것을 짐작할 수 있다. 



게임 데이터 분석을 하는 과제는 이 수많은 데이터를 어떻게 활용할 것인지, 어떤 그래프를 뽑아내야 할 것인지 생각하는 데에 오랜 시간이 걸린다. 하지만 결국 패턴 및 결과를 찾아냈을 때, 거기서 오는 성취감이 정말 큰 것 같다. 

어렵지만 재미있는 과제였다.  




지난 해에 들었던 '소프트웨어 신기술특론(게임 편)' 수업에서는 즐기기만 했던 게임의 형태를 분류하고, 직접 평가해보는 시간을 가졌었다. 또한 가상으로 게임회사 지원을 위한 자기소개서를 써보며 '게임'에 대해 많이 이해하게 되었다. 


이번 학기에는 UI/UX의 인문학적 기능과 게임 데이터 분석을 배우고 있다. 정말이지 많많치 않은 주제다. 

게임을 인문학적으로 파헤치기도 쉽지 않았지만 가장 어려운 것은 단연코 게임 데이터 분석이었다.아직 R을 다뤄보지 않은 나에게 편리한(?) 데이터 분석 tool로 게임 데이터 분석을 하는 것이 과제로 주어졌다. 



주어진 데이터를 통하여 유저 트래픽 관련 분석을 진행하려고 한다.

(주어진 데이터 : user id, ip address, mac address, gender, level, regdate(접속 시간))


여기서 잠깐 ! 

IP address MAC address 의 차이점을 알아보자.

 

IP address 컴퓨터가 인터넷과 연결될 때 받는 고유번호로 전화번호 와 같다. but, 고정값은 아님.

MAC address 는 인터넷에 연결되는 개별 단말기들을 식별할 수 있는 주소이다. 인증 과정에 사용되는 주민등록번호 와 같다. 


(안타깝게도, 위 두 데이터는 주로 어뷰징에 쓰이는 것 같아 데이터 분석 시 건드리지 않았다.)



이번 포스팅에서는 Excel 피벗으로 데이터를 분석해 보겠다. 


▶ User id를 이용하여 일자 별 접속 기록 패턴 얻기 




Excel의 date, hour, concatenate함수는 기본적인 함수이지만 이를 통해 일자별 접속 유저 기록을 얻어내는 것은 쉽지 않았다. 

다음 포스팅에는 같은 데이터를 가지고 빅데이터 분석 툴인 Spotfire로 데이터 분석을 시도해 보겠다. 


▶ 클래스의 선언 

 private로 선언

 public으로 선언

 - 해당 멤버가 속한 클래스의 멤버함수에서만 사용 가능

 - 일반적으로 멤버변수를 private로 사용 

 - 객체를 사용할 수 있는 범위라면 어디서나 접근이 가능한 공개된 멤버

 - private 멤버변수를 처리하기 위한 목적으로 작성하는 멤버함수는 일반적으로 public 멤버로 설정 



▶ 클래스 멤버함수 정의하기 

#include
using namespace std;

class CRect {
	int left, top, right, bottom;
public:
	void print();
	void SetRect(int l, int t, int r, int b);
};

void CRect::print() {
	cout << "(" << left << "," << top << "," << right << "," << bottom << ")" << endl;
}

void CRect::SetRect(int l, int t, int r, int b) {
	left = l,
	right = r;
	top = t;
	bottom = b;
}

void main() {
	CRect rc;
	rc.SetRect(0, 0, 20, 20);
	rc.print();
}

위와 같이 결과는 SetRect()를 멤버함수로 정의한 것에 메인에서 rc.SetRect(0,0,20,20)을 대입한 값이 나온다. 




▶ 생성자와 소멸자 

생성자는 클래스에서 객체를 생성할 때, 기본 자료형처럼 초깃값을 주는 것을 말한다. 

① 생성자는 클래스명과 동일하다. 

② 생성자는 자료형(반환값의 유형)을 지정하지 않는다. 


따라서, 객체가 생성될 때에 멤버변수에 특정 값을 저장하려면 매개변수가 없는 생성자를 재정의 해주어야 한다. 

생성자가 객체를 초기화하기 위한 멤버함수라면 소멸자는 객체를 정리해주는 멤버함수이다. 


구조체 선언은 struct 구조체명; 으로 한다. 

예를 들면, man.name; 에서 

man : 소속 구조체 변수명, name : 멤버변수 라고 할 수 있다. 


구조체 포인터를 매개변수로 사용하는 함수를 작성할 때에는 

(*p).namep→name 으로 간략하게 표현할 수 있다. 약속으로 규정된 것이다! 



▶ 구조체 배열로 5명의 성적을 입력받아 총점, 평균 출력하기 

#include
using namespace std; 
struct score {
	char name[20]; 
	int kor, eng, mat, tot; 
	double avg; 
};

void main() {
	struct score stu[5]; 
	int i; 

	for (i = 0; i < 5; i++) {
		cout << "이름을 입력하시오->"; 
		cin >> stu[i].name; 
		cout << "국어점수를 입력하시오->";
		cin >> stu[i].kor;
		cout << "영어점수를 입력하시오->";
		cin >> stu[i].eng;
		cout << "수학점수를 입력하시오->";
		cin >> stu[i].mat;

		stu[i].tot = stu[i].kor + stu[i].eng + stu[i].mat; 
		stu[i].avg = stu[i].tot / 3.0; 
	}

	cout << "\t 이름  \t 국어    \t영어    \t수학  \t   총점    \t 평균";
	cout << "\n =========================================\n";

	for (i = 0; i < 5; i++) {
	cout << "\t" << stu[i].name << "\t" << stu[i].kor << "\t" << stu[i].eng << "\t" << stu[i].mat << "\t" 
		<< stu[i].tot << "\t" << stu[i].avg;
	}

}

이런 식으로 이름과 점수를 다섯 번 입력할 수 있게 되어있다. 

위와 같이 결과는 학생 당 이름, 국어, 영어, 수학, 총점, 평균 순으로 출력된다. 



성적관리를 위한 구조체를 사용할 때에는 위와 같이 score라는 이름의 구조체를 정의하고, stu[5]라는 이름의 성적을 입력받을 5칸을 만들어준다. 

또한, tot(총점), avg(평균)는 메인 함수에서 계산하여 구하게 된다. 

계산에 쓰이는 변수들은 score 구조체 내에서 name[20]과 같은 배열 크기 지정 없이 kor, eng, tot 등으로 입력해 주어야 프로그램이 작동된다는 것을 명심하자. 


앞서 포인터와 관련된 포스팅의 연장선, 배열을 포인터에 적용해 보겠다. 

& 연산자는 중복 불가이고, * 연산자는 중복 가능이다. 


*a == *&a[0] == a[0] 

이와 같이 배열의 시작주소는 포인터의 값과 같다. 

배열 첨자가 i인 원소의 주소는 &a[i] == a+i 로 나타낼 수 있다. 



이를 2차원 포인터와 연관지어 생각하면 

 ex) int *p;

   int **pp;

   p = &a;

   pp = &p; 

이 예제에서 유추할 수 있는 관계는 다섯가지이다.


⑴  p = &a             변수 p는 변수 a의 주소 저장

⑵  *p = a              *p는 a와 동일한 일반 변수

⑶  pp = &p            pp에 저장된 주소는 1차원 포인터 변수 p의 주소

⑷  *pp = p = &a     변수 a의 주소

 **pp = *p = a


포인터 배열을 사용하는 것은 다음 포스팅에서 함수 포인터와 함께 예시를 제시하겠다. 


포인터 기본 

 & 변수명 : 어느 곳에 위치해있는지 주소값

* 포인터 변수명 : 해당 주소에 위치한 변수값 

따라서, 

p = &a 주소값을 의미하고, *p = a 변수값을 가리킨다. 



포인터를 사용하는 방식에는 주소에 의한 전달방식과 참조에 의한 전달방식이 있다. 


▶ 주소에 의한 전달방식으로 절댓값 구하는 함수 생성 

return값 없어 함수에서만 변환값 출력 가능 

#include 
using namespace std; 
void absolute(int *abs); 
void main() {
   int a = -10; 
   absolute(&a); 
   cout << "main에서 함수 호출 후 a값 = " << a << "\n"; 
}

void absolute(int *abs) {
   if (*abs < 0)
      *abs = -*abs; 
}




▶ 참조에 의한 전달방식으로 절댓값 구하는 함수 생성 

참조 변수는 선언할 때만 일반 변수 선언과 달리 변수명 앞에 &기호를 붙일 뿐 프로그램 상에서는 일반 변수를 동일하게 사용한다. 

#include

using namespace std; void absolute(int &a); void main() { int a = -10; absolute(a); cout << "main에서 함수 호출 후 a 값 = " << a << endl; } void absolute(int &a) { if (a < 0) a = -a; }

소스를 보면 둘의 다른 점을 알 수 있을 것 같아 예시부터 제시했다. 물론 두 코딩의 결과는 동일하다. 

늦은 포스팅이 되었다. 목표는 매주 과제를 끝마치고, 복습 겸 블로그에 포스팅까지 마치는 것이였는데 포인터를 하면서 무너지게 되었다... 

어마무시한 포인터와 관련한 포스팅은 [함수]편 바로 다음에 올라갈 예정이다! 



함수의 장점은 반복 실행해야만 하는 내용을 필요할 때마다 호출해서 사용 가능하고, 프로그램의 기능 및 구조를 알아보기 쉽다는 점 ! 

함수를 선언할 때에는 함수 정의 전 호출이 되었다면 그 함수를 main 함수 위에 반드시 선언 후 호출해야한다. 예를 들어보겠다. 

#include

using namespace std; bool isEven(int n); void main() { int n; cout << "짝수, 홀수를 판별할 숫자를 입력하세요->"; cin >> n; if (isEven(n)) cout << "입력하신 숫자는 짝수입니다." << endl; else cout << "입력하신 숫자는 홀수입니다." << endl; } bool isEven(int n){ if (n % 2 == 0) return true; /* 부울형의 사용법 : 짝수가 맞으면 true */ else return false; /* 짝수가 아니라면 false 출력 */ }


위와 같이 main() 함수에서 아직 정의되지 않은 isEven(int n)함수를 호출했으므로 반드시 main() 위에 부울형 함수인 bool isEven(int n)을 선언해주어야 하는 것이다. 



이번에는 함수가 main함수보다 먼저 입력된 경우를 살펴보자. 

#include
using namespace std;

double avg(int a, int b) {
	double s;
	(double)s = ((double)a + (double)b) / 2; 
	return s; 

}
void main() {
	int a, b; 
	double res; 
	cout << "숫자 두개를 입력하세요:"; 
	cin >> a >> b; 
	res = avg(a, b); 
	cout << "평균 : " << res << endl; 
}

위의 코드는 굳이 함수를 먼저 선언하지 않아도 된다. 여기서 return s;에 주목해보자!

함수의 실행결과를 반환하고자 할 때에는 return문을 사용하는데 기본 형식은 return 식;이다. 

또한, 함수를 호출할 때 기술되는 실 매개변수와 함수를 정의할 때 기술되는 형식 매개변수, 이 두 변수명이 꼭 동일할 필요는 없다. 어차피 전혀 다른 기억공간이 따로 할당되어 값을 복사하기 때문이다. 


html만을 이용하여 로그인 및 쇼핑몰 홈페이지를 만들어보았다. 

우리가 사용하는 웹 사이트와는 비교할 수 없을 정도로 낮은 수준이지만 과제를 하면서 html의 원리 및 여러 태그, 특히 입력 폼에 대한 공부를 확실히 할 수 있었다. 

CSS, javascript를 배우기 전이라면 한번쯤 먼저 html만을 이용한 홈페이지를 만들어보고, 그 후 배운 것들을 덧붙여 발전하는 나의 홈페이지를 직접 확인해보는 것도 좋은 방법인듯 싶다. 



아이디, 비밀번호, 학번, 이름 입력 폼 등을 사용하고 '로그인' 버튼 클릭 시 환영 메세지를 띄웠다. <mark>(형광펜 기능) 태그가 되어 있는 'market'을 클릭하면 쇼핑몰 홈페이지로 넘어간다. 

사용자 입력을 위한 <input> 태그를 주로 사용하였다.


<input type="search"> : 검색 상자 만들기 

<input type="date"> : 날짜 표시하기 

<img src="사진 경로.jpg" alt="(사진 대체용)이미지 설명 텍스트"> : 이미지 첨부 

<a href = "링크"> 내용 </a> : 링크 만들기 



쇼핑몰 홈페이지에서는 기타 다양한 폼을 사용해 보았다. 


<input type="radio"> : 주어진 항목 중 1개만 선택 가능한 라디오 버튼 넣기 → 메일링 서비스 내 할인 상품 or 인기 상품 선택

readonly : 읽기 전용 필드 만들기 → market 이용가능시간 

<select>, <option> : 드롭다운 목록 만들기 → 종류 및 가격 분류의 여러 옵션 중 한가지 선택 

<progress> : 진행 상태 보여주기 → 오늘의 꽃 업데이트 현황 

<meter> : 값이 차지하는 크기 표시 → 누적판매량 및 스페셜 척도 표시 


이 외에도 여러 폼을 사용하였다. 얼른 CSS도 숙달해 와야겠다. 무엇보다도 아직까지는 칸을 나누는 것을 표만들기로 할 수 밖에 없다는 것이 함정... 큰 홈페이지를 구상하는데 표로 하니 엄청 막막했다. 

레이아웃의 필요성을 느껴보라고 내주신 과제인 듯 하다.하하하... 

회원가입

로그인 정보
개인정보

간단한 회원가입 입력창 만들기

2주 전부터 폼 관련 태그들을 익혔다. 


아이디 및 비밀번호를 입력할 수 있는 로그인 창, 달력, 버튼 넣기, 진행 상태 표시 등등의 여러 폼이 있었다.


아직 css의 진도를 나가지않아 스타일 지정은 역부족이였지만 이제 html5을 활용하여 어느정도을 구성할 수 있다!

다음 주차 목표는 html만을 이용하여 로그인 홈페이지, 쇼핑몰 홈페이지를 만들어보는 것이다



제어문에는 if문, if~else문, switch문, for문, while문 등이 있다.


▶ 아스키코드를 활용하여 알파벳 A부터 Z까지 출력 받는 코드

#include
using namespace std;
void main() {	
	int i; 

	for (i = 65; i <= 90; i++)
		cout << (char)i; 
}

for문의 구성은 for(초기식; 조건식; 증감식)으로 구성되는데 만약 조건이 필요하지 않다면 for( ; ; )로 입력해주면 된다.



사실 for문 자체는 그닥 어렵지 않은데 다중 for문이 적용되었을 때 서로 다른 루프(loop) 를 잘 구별해야 하는 것이 관건이다.


▶ *로 역삼각형 모양을 만들어 출력하는 프로그램

 #include
using namespace std; 
void main() {
	//17번 
	int  i, j;

	for (i = 5; i > 0; i--) {  // i는 5,4,3,2,1 순으로 
		for (j = 1; j <= i; j++)  // j는 1,2,3,4..i가 종료될 때까지이므로 5줄까지 입력됨 
			cout << "*";  // i수 만큼 * 이 입력됨 -> '문장 1' 
            cout << "\n"; 
	}	
} 


안쪽에 기술된 for문 안의 '문장 1'은 (바깥쪽 for문의 반복횟수) * (안쪽 for문의 반복횟수) 만큼 반복된다.

유의하자!




▶ 단이 바뀔 때마다 오른쪽으로 이동하는 구구단 프로그램 

#include
using namespace std; 
void main() {
	 //27번 구구단 출력 
	int dan, j; 

	for (dan = 1; dan <= 9; dan++) {
		for (j = 2; j < 10; j++) {
			cout << j << "*" << dan << "=" << j*dan <<"\t" ;//\t는 tab기능
		}
		cout << "\n";  // 안쪽 for문이 한 번씩 돌아가고, 바깥쪽 for문의 dan++이 실행될때마다 줄바꾸기 
	}
	} 


단이 바뀔때마다 오른쪽으로 출력되도록 이중 for문을 설정해 주었다. 






개발 환경은 Visual Studio Code

정말 기본적인 태그를 다룰 것이다. 


<h1>, <h2>, ... <h6> : 제목 텍스트. 숫자가 작을수록 제목이 큰 것이다. 

<ul>, <li> : 순서가 없는 목록 만들기.

<ol>, <li> : 순서가 있는 목록 만들기.


▶ 순서가 없는 목록 만들기를 이용한 자기소개


 



기본적인 nxn 만들기

1. <table> 태그로 표자리 만들기 

2. <tr> 태그로 n개의 행 만들기 

3. <td> 태그로 각 행마다 셀 n개씩 추가 

행 또는 열을 합치는 태그의 기본형은 

<td colspan = "합칠 열의 개수"> 내용 </td>, <td rowspan = "합칠 행의 개수"> 내용 </td>


표만들기 를 응용한 예제를 스스로 만들어보았다. 

▶ 행 또는 열을 합치는 기능을 활용한 표만들기 



먼저 표의 첫 줄 칸을 보고 어떤 행을 합쳐야하는지를 파악하여 적재적소에 rowspan, colspan을 배치해야한다. 
실행결과를 보면 첫 줄의 '1'과 '2' 칸은 그대로이고, '3' 칸에 2개의 행을 합쳤다. (rowspan)
두번째 줄에서는 '4칸에 2개의 행을 합쳤고(rowspan), '5' 칸은 그대로이다. 
세번째 줄에서는 '7' 칸에 2개의 열을 합쳤다(colspan). 

헷갈리지 말 것 !






기본적인 '입출력'부터 '정수형'과 '실수형'의 표현, 기본 연산자에 대해 다루었다.

 

▶ 관계 연산자와 논리 연산자를 사용한 예제

   논리형의 종류

 종류

 의미

 ||

 논리합 연산자(AND)

 &&

 논리곱 연산자(OR)

 !

 논리 부정 연산자(NOT)

위의 예제에서  bool은 C와 달리 C++에만 있는 '참과 거짓을 나타나내는 논리형 변수'이다.

 

▶ 전위(증가)연산자 / 후위(증가)연산자

실행문에서 변수 값의 증가 이후 문장이 실행되면 전위증가연산자이고,

실행문의 완료 이후에 변수 값이 증가하면 후위증가연산자이다.

 

▶ 아스키코드 대(소)문자 변환(조건연산자 사용)

문자를 2진수로 저장하기 위해 컴퓨터는 문자마다 대응되는 수치 데이터를 정해 두었다. 이를 '아스키코드' 라고 한다.

대문자는 65 ~ 90 으로 지정되며 소문자는 97 ~ 122로 지정된다.

아스키코드의 대문자 'A'는 65, 소문자 'a'는 97로 아스키코드 값이 32만큼 차이 나는 점을 활용하여  대문자를 소문자로 변환하는 프로그램을 출력 가능하다.  

위의 코드에서는 먼저, 입력받은 문자가 대문자의 범위 내에 있는지 확인하는 조건 연산자가 쓰였는데

조건식의 결과가 '참'이면 32를 더해 소문자를 출력했고, '거짓'이면 기존 입력값(소문자)이 그대로 출력되도록 하였다.

+ Recent posts