각 분석 방법론과 알고리즘을 사용하는 사례를 찾기 → 논문(RISS) or 저널 국내 : <지능정보연구> <한국경영과학회지><Information Systems Review> 해외 : <IEE Access> <IEEE Transactions on Big Data> <Information Systems Research>
카테고리는 컴공, 수학, 통계, 산업공학 보다는 정보시스템학 계열을 선택
실질적으로 도움이 되는 최소한의 자격증
한 번에 몰아서 딸 것준전문가, 2급정도만 할 것
데이터 분석 자격검정 & 경영빅데이터 분석사 동시준비 사회조사분석사 (필기 - 조사방법론 1 필요없고, 2가 중요하다) SQL 자격검정 - (데이터 모델링, SQL쿼리 중점) <SQL 전문가 가이드> (한국데이터베이스진흥원)
수학
책에선 개론책을 추천했는데, 나는 아래의 두 책을 읽을 것이다.
<프로그래머를 위한 선형대수학> <데이터 과학을 위한 통계: 데이터 분석에서 머신러닝까지 50가지 핵심 개념>
기본적인 딥러닝에 관한 서적을 읽어라
1. 책으로 딥러닝 공부하기 <딥러닝 제대로 시작하기>(제이펍) 2. 강의로 딥러닝 공부하기 <김성훈 교수 - 딥러닝 강좌> 3. 좀 더 깊게 공부하기 <밑바닥부터 시작하는 딥러닝> 4. 이후 CNN LSTM 오토인코더 GAN 등 다양한 딥러닝 모델 공부, 실제 코드도 구현 4-1 딥러닝 구현 라이브러리 (텐서플로우 케라스 카페 파이토치 티아노 중 택 1) <케라스 창시자에게 배우는 딥러닝> 강추
월가아재 추천 <SQL in 10 Minutes Sams Teach Yourself> 을 읽으려 했으나,
SQL 자격검정 시험을 보면서 찍먹 후 쉬운 책으로 공부할 계획이다.
Part 4 자신만의 전문분야를 선정하라
캐글 경연대회를 통해 경험을 쌓으라
최대한 다양한 분야의 연구를 해보라
캐글 필사→ 라이브 대회 참여, 디스커션 공부 → 라이브러리, 논문 → PPT 정리
자신만의 연구 분야를 선정하라
[기술] 이미지분석 딥러닝 금융공학 이상탐지 추천알고리즘 텍스트 마이닝
[현상] 정치 금융 생명 등등
기술 파트에는 시계열 데이터, 회귀분석 현상은 금융공학에 관심이 많다.
전문분야에 대한 서적을 읽어라
아마존 닷컴에서 기술이나 현상 분야의 심도있는 책들을 찾을 수 있따. *상세한 설명이 있는 꽤 두꺼운 책을 읽어라 *교수가 쓴 책보다 현업 개발자가 쓴 책을 사라
전문 분야에 대한 논문을 읽어라
최신 트랜드는 논문이 책보다 훨씬 빠르다 *기억에 남기는 논문읽기 *자신만의 정리 방법을 반드시 가질 것
1. 논문 맨 앞 표지에 해당 논문의 가장 핵심적인 아이디어를 간단히 요약 2. 괜찮다 싶은 아이디어는 나만의 아이디어 노트에 따로 정리 3. 인용이 많이 되었거나 해당 연구 분야에서 핵심적인 아이디어를 제안했던 논문들은 따로 워드테이블로 정리 (저자, 제목, 연도, 연구목적, 연구 방법) 검색 시 노무 많은 논문이 나와 뭐부터 읽어야 할지 모르겠다면 1. 인용수가 많은 논문 2. 최신 경향을 익히기 위해 가장 최근인 논문 3. 선행 연구 부분이 자세하게 나와 있는 논문순으로 읽는다
주 프로그래밍 언어를 선정하고 관련 프로젝트를 반복 훈련해라
[실전 프로젝트 경험을 쌓는 방법] 1. 회사 취업 2. 플리랜서로 활동 - 대학생 숙제, 재능플랫폼에서 활동 3. 자체 프로젝트 수행 - sns 웹 크롤링
자신만의 독창적인 알고리즘을 만들어 보라
기존의 아이디어에 자신의 아이디어를 얹어라 -메타분석을 한 기존 논문을 읽어라 * 기존 문헌들을 분석후 연구 트렌드와 연구가 부족한 부분을 연구하는 방법이다. -구글 학술검색에서 검색 시 Literatrue Review 라는 키워드를 함께 넣어 주자 -하나의 알고리즘 보다는 두 개 이상의 알고리즘을 써라
한국 학술지 인용색인 등재지에 도전하라
1. 논문 투고 타깃 저널을 정하라 i. 자신이 자주 읽어보았던 논문들이 주로 어떠한 저널에 실려있었는지 확인
ii. 저널마다 각기 선호하는 논문의 성격이나 주제가 있을 수 있다 == 내 논문도 이 저널에 실리기 유리하다
2. 바로 논문 작성을 해보라
i. 논문 작성 전 벤치마킹할 논문을 정한다. (표절하라는 뜻이 아니다.)
크게 분류 해보면
경영학 도서 / 코딩 / 데이터 마이닝
SQL / 수학 / 딥러닝 / 자격증
관심 분야 /프로젝트 / 논문이고
자격증, 프로젝트, 논문 같은 경우 당장 시작하기에 부담이 있기에
추천도서, 코딩, 수학, 딥러닝, 관심 분야(금융공학) 정도는 1년동안 부담없이 공부할 수 있을 것 같다.
# Feature Scaling 과정
def feature_scaling(X ,n):
mean = X.mean(axis = 0)
std = X.std(axis = 0)
#intercept 특징은 Feature Scaling 과정이 필요 없기에 1부터 시작
for i in range(1,n-2):
#각 특징 별 평균과 표준편차를 구한다.
m = mean[i]
s = std[i]
#Feature Scaling
X.iloc[: ,i] = (X.iloc[: ,i] - m) / s
return X
X = feature_scaling(tmp.iloc[: ,1:n-1] ,n)
# Y의 type이 series 1차원 형태이므로 2차원 형식으로 변환한다.
Y = tmp['price'].values.reshape(m,1)
X.head()
class TrieNode
{
public:
// TrieNode 객체 생성
bool finish; //글자의 끝의 유/무 를 finish로 설정
TrieNode *children[26]; //26개의 자식 노드 생성 ('a~z')
TrieNode() //각 노드의 초기값 설정
{
finish = false;
for (int i = 0; i < 26; i++)
children[i] = NULL;
}//처음 아무것도 없는 상태이므로 각 노드의 끝을 false와 NULL로 설정
};
class WordDictionary {
public:
WordDictionary()
{
root = new TrieNode(); //Trie 생성
}
void addWord(string word)
{
int word_len = word.length(); //단어의 길이
int k = 0; //string -> int 알파벳 a~z 를 index로 사용하고자 k = 0~25 로 선언
TrieNode *cur = root; //탐색노드 cur에 초기 TrieNode 대입
for (int i = 0; i < word_len; i++) //단어의 한 글자씩 Trie 에 추가
{
k = word[i] - 'a';
if (cur->children[k] == NULL)
{
cur->children[k] = new TrieNode();
}////해당 trie가 아무것도 없는 상태라면, 새로 하위 노드 생성
cur = cur->children[k]; //다음 node로 이동
}
cur->finish = true; //단어의 끝 finish 값을 true로 설정
}
bool search(string word)
{
return searchHelper(word, root); //parameter를 수정한 search 함수
}
private:
TrieNode* root; //root 생성
bool searchHelper(string word, TrieNode* current)
{
for(int i = 0; i < word.size(); i++)
{
if(word[i] != '.'){ //기존 search 방식과 동일
if(!current->children[word[i] - 'a'])
return false;
current = current->children[word[i] - 'a'];
}
else
{ // '.'이 단어 중간에 있는 경우
for(int j = 0; j < 26; j++) // 다음 자식 노드 26개 모두를 탐색
{
if(current->children[j] && searchHelper(word.substr(i + 1), current->children[j]))
{ //다음 자식노드가 존재하고, 이후 다음 글자들이 Trie에 있는지 재귀로 탐색
return true; //하나라도 만족하면 true리턴
}
}
return false;
}
}
return current->finish; //'.'이 없는 경우 단어의 끝에 해당하는 Trie->finish 값 리턴
}
};
Trie Tree를 생성하고, 삽입, 검색, 접두사 검색 (검색엔진의 자동완성) 함수를 구현한다.
Organizing thoughts
Trie에 관한 내용은 아래 블로그를 참고하였다.
Sourcecode
##source code 출처
class TrieNode {
public:
// TrieNode 객체 생성
bool finish; //글자의 끝의 유/무 를 finish로 설정
TrieNode *children[26]; //26개의 자식 노드 생성 ('a~z')
TrieNode() //각 노드의 초기값 설정
{
finish = false;
for (int i = 0; i < 26; i++)
children[i] = NULL;
}//처음 아무것도 없는 상태이므로 각 노드의 끝을 false와 NULL로 설정
};
class Trie {
public:
Trie()
{
root = new TrieNode(); //Trie 생성
}
// 단어를 Trie에 Inserts
void insert(string word)
{
int word_len = word.length(); //단어의 길이
int k = 0; //string -> int 알파벳 a~z 를 index로 사용하고자 k = 0~25 로 선언
TrieNode *cur = root; //탐색노드 cur에 초기 TrieNode 대입
for (int i = 0; i < word_len; i++) //단어의 한 글자씩 Trie 에 추가
{
k = word[i] - 'a';
if (cur->children[k] == NULL)
{
cur->children[k] = new TrieNode();
}////해당 trie가 아무것도 없는 상태라면, 새로 하위 노드 생성
cur = cur->children[k]; //다음 node로 이동
}
cur->finish = true; //단어의 끝 finish 값을 true로 설정
}
//search 하는 단어가 Trie내에 있다면 true 없다면 false 리턴
bool search(string word)
{
int word_len = word.length();
int k = 0;
TrieNode *cur = root;
for (int i = 0; i < word_len; i++)
{
k = word[i] - 'a';
cur = cur->children[k];
if (cur == NULL)
return false;
}
return cur->finish;
//insert 글자의 끝 부분을 true로 했을 경우 true 리턴이고
//아닐 경우 defalut값이 false이므로 false리턴
}
//prefix를 가지는 글자가 있는지 탐색
bool startsWith(string prefix)
{
int word_len = prefix.length();
int k = 0;
TrieNode *cur = root;
for (int i = 0; i < word_len; i++)
{
k = prefix[i] - 'a';
cur = cur->children[k]; //찾는 단어의 글자 순으로 탐색
if (cur == NULL) //Trie가 NULL이거나,
//탐색할 다음 글자의 node가 NULL인 경우 false return
return false;
}
return true; //defalut 값 true
}
private:
TrieNode* root; //root 생성
};
class Solution {
public:
int kthSmallest(TreeNode* root, int& k)
{
if (root)
{
int x = kthSmallest(root->left, k);
return !k ? x : !--k ? root->val : kthSmallest(root->right, k);
}
else return NULL;
}
};
위 코드는 가독성이 떨어져 가독성이 좋은 코드를 찾아 해설해보았다.
class Solution {
public:
int kthSmallest(TreeNode* root, int k) {
return dfs(root, k);
}
int dfs(TreeNode* node, int& k) //int k 가 아니라 int& k 를 사용해 k값을 직접 변경한다.
{
if(!node) return NULL; //node가 없다면 null 리턴
int l = dfs(node->left,k); //BST 구조이므로 중위순회
if(k == 0) return l; //전달 받은 node->val 값 리턴, root로 다시 돌아올 때 k가 0인 상태가 된다.
else if(k == 1) //k가 1일 때의 값이 k번 째 값이므로
{
k--; //k를 0으로 만들고, 정답 리턴
return node->val;
}
else // k가 1보다 크면,
{
k--; //k를 1 줄이고 (탐색했다는 흔적)
int r = dfs(node->right,k); //오른쪽으로 중위순회를 이어나간다.
if(k==0) return r; //오른쪽 탐색결과 정답을 찾았으면 정답 값 리턴
else return NULL; //오른쪽이 빈노드거나 오른쪽을 탐색해도 못찾으면, null 리턴
}
}
};
class Solution {
vector<TreeNode*> nodes;
public:
bool isSubtree(TreeNode* s, TreeNode* t) {
if (!s && !t) return true; //둘다 null이면 true
if (!s || !t) return false; //하나만 null이면 false
getDepth(s, getDepth(t, -1)); //s의 깊이를 구하고, s의 깊이에 해당하는 node저장
for (TreeNode* n: nodes) //저장한 node들과 s가 같은지 확인
if (identical(n, t))
return true;
return false; //defalut 값 false
}
int getDepth(TreeNode* r, int d)
{
if (!r) return -1;
// -1인 이유 : 1. 가장 아래서부터 높이를 더하기 때문
//2. t에서 s와 높이가 같은 노드를 저장해야 하는 데,
// s의 높이를 구하는 과정에서 d가 0보다 클 경우,
// 저장 node에 s의 node가 들어가는 것을 막고자
int depth = max(getDepth(r->left, d), getDepth(r->right, d)) + 1;
//중위순회하며 높이 구하기
if (depth == d) //t-node 의 높이가 s의 높이와 같다면 해당 t-node 저장
nodes.push_back(r);
return depth;
}
bool identical(TreeNode* a, TreeNode* b)
{
if (!a && !b) return true; //둘다 null이면 true
if (!a || !b || a->val != b->val) return false;
//하나만 null이면 혹은 둘의 값이 다르면 false
return identical(a->left, b->left) && identical(a->right, b->right);
//false 가 하나라도 잡히면 false 리턴
}
};
class Solution {
public:
vector<vector<int>> ans; //정답 벡터
int max_depth = 0;
//resize가 줄어들게 되면, 기존 값들이 다 없어지기에, 최대 size를 유지해준다.
vector<vector<int>> levelOrder(TreeNode* root)
{
if(!root) return ans; //빈 트리면 null 리턴
ans.push_back(vector<int>()); //행 추가
ans[0].push_back(root->val); //root 값 추가
insert(root->left,1); //재귀로 깊이 탐색
insert(root->right,1);
return ans;
}
void insert(TreeNode* root, int c)
{
if(!root) return;
else
{
max_depth = c > max_depth? c : max_depth; //깊이가 늘어나면 최대 깊이 수정
ans.resize(max_depth+1); //최대 깊이에 맞게 size 수정한다.
ans[c].push_back(root->val); //레벨에 맞는 곳에 값 추가
insert(root->left,c+1);
insert(root->right,c+1);
}
}
};
New things learned
c++ resize를 사용시 size가 5였다가 3으로 다시 준다면, size가 5였을 때 값은 다 날라간다.