BLOG main image
FunnyPR (32)
OpenGL (20)
PatternRecognition (7)
Tips (2)
XML (1)
DataMining (1)
Visitors up to today!
Today hit, Yesterday hit
daisy rss
tistory 티스토리 가입하기!
2017. 2. 3. 15:11
오랜만에 글쓰네...

Random forest 개념을 이해하다 보면 purer, impurity 라고 나온다. 


갑자기 이런 말이 나오니 당황 스럽다. 


이 개념을 자세히 다룬 곳이 없어 내가 정리하기로 했다. 


우선 impurity 라는 단어에 대한 이해가 필요하다. 


impurity 는 불순물, 불결, 불순 개념이다. 그림에서 보면 유리 병에 불순물이 섞여 흐릿하게 보이는 것을 알 수 있다. 


impurity water에 대한 이미지 검색결과


랜덤 포레스트는 impurity 라는 개념을 사용하여 가지를 치는(생성하는) 기준을 설정한다. 

분지 기준(splitting criterion) 이라고 하는데 한국 단어는 한자의 개념이 함께 있어 한번에 이해하기 더 어렵다. 


본론으로 들어가 그럼 왜 impurity 라는 개념을 쓸까 다음 그림을 보면서 이해하자 

우선 G 수치는 무시하고 그림만 보자 그림에서 빨간색이 사건 A 라고 하고 파란색을 사건 B 라고 하자 

제일 위 왼쪽 상자에 10개의 파란색 네모가 있다. 파란색 관점에서 보면 순수하다. pure 하다는 것이다. 즉, 반대로 말하면 불순물이 없다는 것이다. 따라서 G=0 으로 볼 수 있다. 


파란색 네모 입장에서 보면 빨간색 네모는 불순물과 같은 존재이다. 자기 존재를 흐리게 만드니깐. 췌


이러한 개념에서 아래와 같이 우리는 해석할 수 있다. 

빨간색(0), 파란색(10) = 불순물이 없네~~~

빨간색(1), 파란색(9) = 어라 불순물이 하나 생겼네!

빨간색(2), 파란색(8) = 흠 불순물 더 생겼어!

빨간색(3), 파란색(7) = 또 분순물이 증가했군!

빨간색(4), 파란색(6) = 머야 또 늘었어!

빨간색(5), 파란색(5) = 하 머야 엄청 늘었잖아!!!

....


자 이것을 보기 좋게 수식으로 전개한 것이 Gini impurity 이다. Gini impurity 를 해석해서 쓰진 않겠다. 

왜냐면 내 마음이니깐. 여기서 Gini 는 그 주전자 문지르면 나오는 아이 아니다. impurity 수식을 제안한 학자 이름이니 나중에 행여 발표하게 되면 약간의 위트 있는 개그를 해 주면 좋을 것이다. 


본격적으로 Gini impurity 수식을 보자 . 짜잔 ~~



어려워 하지 말자. 우선 J 는 사건의 수를 말한다. 빨간 네모가 일어날 사건 한개 파란색 네모가 일어날 사건 한개, 위에서 언급한 예제의 사건은 총 2개이다. 

J 는 사건의 수를 나타낸다. 즉, 예제에서는 2가 된다. 

pi 는 i 번째 사건의 요소들이 일어날 확률이다. 

1-pi 는 i 번째 해당하는 사건들이 일어날 확률의 여사건 확률이다. 그러니깐 i 번째 해당하는 사건이 일어나지 않을 확률이다. 

수식에서 보면 pi 와 1-pi 는 독립사건이다. 이유는 pi 가 일어날 사건과 안일어날 사건(1-pi) 는 서로 연관이 없으며 독립적으로 발생하기 때문이다. 


: 확률에 대한 설명은 재미도 없고 고달프다. 아마도 이글을 보는 사람은 개념만 이해하고 싶을 것이다. 

따라서 위 수식을 예제에 적용한 결과를 바로 제시한다. 


A

B

P1

1-P1

P2

1-P2

P1(1-P1)

P2(1-P2)

G

0

10

0

1

1

0

0

0

0

1

9

0.1

0.9

0.9

0.1

0.09

0.09

0.18

2

8

0.2

0.8

0.8

0.2

0.16

0.16

0.32

3

7

0.3

0.7

0.7

0.3

0.21

0.21

0.42

4

6

0.4

0.6

0.6

0.4

0.24

0.24

0.48

5

5

0.5

0.5

0.5

0.5

0.25

0.25

0.5

6

4

0.6

0.4

0.4

0.6

0.24

0.24

0.48

7

3

0.7

0.3

0.3

0.7

0.21

0.21

0.42

8

2

0.8

0.2

0.2

0.8

0.16

0.16

0.32

9

1

0.9

0.1

0.1

0.9

0.09

0.09

0.18

10

0

1

0

0

1

0

0

0


위에 표에서 이해를 돕기 위해 아래에 한줄 더 추가 했다. (나의 배려심은 끝이 없군)



위 예제에서 빨간색 네모가 4개 그리고 파란색 네모가 6개 일 경우 그 불순한 정도(Gini impurity) 는 0.48 이다. 가장 많이 불순하다고 보는 것은 두 사건 요소들이 1:1의 비율로 섞여 있을때이다. 이때 Gini impurity 는 0.5 값이다. 


위 표와 함께 Gini impurity 는 해석은 Gini impurity 값이 클 수록 내가 가진 메트릭의 불순도가 높은것이며, 작을수록 순수하다는 것이다. 



그럼 이 개념이 왜 Random forest 에 사용되는 것일까? 


RF 모델 개념에서 보면 자식 노드는 부모 노드 보다 순도가 높아야 한다고 한다. 말로 하지 말고 그림으로 보자 



위 그림에서 G 가 Gini impurity 값이다. 부모 노드가 제일 위에 있는데 G= 0.5 이다. 따라서 불순하다(하앍 나만 변태스러운가....) 

위에서 하나의 기준을 가지고 걸러내면 2개의 네모박스가 걸러지고 나머지 군집에서 다시 Gini impurity 를 계산하면 0.46 이다. 


이 얼마나 아름다운가 부모 노드의 G 가 자식 노드 보다 높다. 랜덤 포레스트 모델링 입장에서 가지를 칠  경우 적어도 식별하고자 하는 타켓을 구분한 후 가지를 쳐야 한다. 따라서 계속 가지를 늘려갈 수록 해당 사건들로 구성된 메트릭스의 불순도는 낮아지게 되는 것이다. 계속 가지를 치는 과정을 반복하면서 랜덤포레스트는 이 불순도를 기준으로 하여 학습을 종료 할 건지 안할 건지 결정하는 것 같다(내 추정).  


대부분의 마이닝 책들이 수식만 제기하고 글로 그 수식을 풀어 헤치고 조건에 대해 냅따 기술해 놓는다. 아놔 그럼 누가 이해하나!! 아마 똑똑한 사람들은 금방하겠지(시무룩)

좀 풀어서 독자가 이해하기 쉽게 써주면 좋을것 같다. 


[참고로 랜덤포레스트 하다 보면 변수들의 상대적 중요성에 대해 그래프를 하나 얻게 되는데 그 그래프에서 Gini 값이 사용된다. 즉 Gini 값을 가장 많이 감소 시키는 변수가 가장 좋은 것이라는 해석이다.]




2014. 12. 15. 14:26

 Wilk's Lambda


1. Wilk's Lambda 란[1]

검증 통계치(test statistics)에서 많이 사용되는 검정 통계량

Wilks lambda ranges from 0 –  1 and the lower the Wilks lambda, the larger the between group 

dispersion.  A small (close to 0) value of Wilks' lambda means that the groups are well separated. A large (close to 1) value of Wilks' lambda  means that the groups are poorly separated.

- 0 ~ 1 사이의 값을 가짐

- 1에 가까우면 그룹들이 잘 분류되지 않음

- 0에 가까우면 그룹들이 잘 분류됨


2. Wilk's Lambda 식 (Λ)


2.1 각 수식에 대한 개념


W: Within-groups sum of squares and cross-products matrix :: 그룹 내 제곱합과 대칭 행렬[2]  

      --> 클래스 내 분산과 같음

B: Between-groups sum of squares and cross-products matrix

      --> 클래스 간 분산과 같음

T: Total sum of squares and cross-products matrix


[note] the cross product matrix X' X is a symmetric matrix.

        - 2 참조 사이트에 가면 sum of square 에 대한 개념과 cross-product matrix에 대한 개념을 이해할 수 있음 


2.2 각 요소에 대한 개념

g: is the number of group(그룹(클래스)의 수)

ni: is the number of observations in the ith group(i 번재 그룹에 속하는 패턴들의 수)

/Xi: The mean vector of the ith group(i 번째 그룹의 평균)

/X: The mean vector of the all the observations(전체 평균)

Xij: The jth multivariate observation in the ith group(i 번째 그룹에서 j 번째 나타난 다변량 관측 값; i행에 j번째 값)


2.3 수식 설명



그림에서 볼 수 있듯이 클래스간 분산(B)를 분모로 넣고 클래스내 분산(W)를 분자로 나누었을 경우 생각해 보면

- 클래스 내 분산이 작고, 클래스간 분산이 크면: 분류 하기 쉬움(결과 값이 작아짐)

- 클래스 내 분산이 크고, 클래스간 분산이 작으면: 분류 하기 어려움(결과 값이 커짐)


즉, Wilk's Lambda 수식에서 Lambda(Λ)의 값이 작을 수록 판별하기 수월한 능력을 가진다라고 이야기 할 수 있음. 


3. 예제 

레퍼런스 2번에 있는 값들을 사용하여 계산해 보자. 초점은 어떻게 Wilk's Lambda를 계산하는가 이다.


Formulation I

Formulation II

Formulation III

Cmax(X1)

AUC(X2)

Cmax(X1)

AUC(X2)

Cmax(X1)

AUC(X2)

0.342

2.1

0.169

1.097

0.091

0.724

0.11

0.747

0.295

1.76

0.264

1.538

0.279

1.833

0.381

2.294

0.463

2.417

0.2

1.32

0.173

1.024

0.19

1.379

0.207

1.245

0.37

2.384

0.101

0.737


step 1: 먼저 아래와 같이 다시 메트릭스를 구성하자.(보기 편하게)


Group

Cmax(X1)

AUC(X2)

0.342

2.1

0.11

0.747

Formulation1

0.279

1.833

0.2

1.32

0.207

1.245

0.169

1.097

0.295

1.76

Formulation2

0.381

2.294

0.173

1.024

0.37

2.384

0.091

0.724

0.264

1.538

Formulation3

0.463

2.417

0.19

1.379

0.101

0.737


step 2: 관련 변수 값 구하기 

A) 평균

Group

Cmax(X1)

AUC(X2)

Formuldation1

0.2276

1.449

 Formuldation2

0.2776

1.7118

 Formuldation3

0.2218

1.359


B) 전체 평균

 

Cmax(X1)

AUC(X2)

Total Mean

2.242333

1.5066


Step 3: T 값 구하기

A) 각 raw 데이터에 컬럼 전체 평균을 빼줌( raw data - mean of each column)

Cmax(X1) 

AUC(X2) 

0.099667

0.5934

-0.13233

-0.7596

0.036667

0.3264

-0.04233

-0.1866

-0.03533

-0.2616

-0.07333

-0.4096

0.052667

0.2534

0.138667

0.7874

-0.06933

-0.4826

0.127667

0.8774

-0.15133

-0.7826

0.021667

0.0314

0.220667

0.9104

-0.05233

-0.1276

-0.14133

-0.7696


- 이름을 Tmatrix 라고 임의로 지정


B) T 값 구하기: Tmatrix' * Tmatrix

여기서 '는 전치행렬(transposed matrix)


수행결과: T=

0.1751

0.9223

0.9223

5.0445


Step 4: W 값 구하기

A) 각 그룹별로 그룹 평균 빼기

Cmax(X1)

AUC(X2)

0.1144

0.651

-0.1176

-0.702

0.0514

0.384

-0.0276

-0.129

-0.0206

-0.204

-0.1086

-0.6148

0.0174

0.0482

0.1034

0.5822

-0.1046

-0.6878

0.0924

0.6722

-0.1308

-0.635

0.0422

0.179

0.2412

1.058

-0.0318

0.02

-0.1208

-0.622


B) 각 그룹별(클래스내) 분산 구하기 

CovG1 = Formuldation1' * Formuldation1

CovG2 = Formuldation2' * Formuldation2

CovG3 = Formuldation3' * Formuldation3


covG1 =

 0.0307 0.1845

 0.1845 1.1223


covG2 =

 0.0423 0.2619

 0.2619 1.6442


covG3 =

 0.0927 0.4203

 0.4203 1.9419


C) 각 그룹 분산 더하기 최종 W 계산

covTotal =

    0.1657    0.8667

    0.8667    4.7084


Step 4: Wilk's Lambda 계산


Λ = |W|/|T|


W = 0.029

T = 0.033


Λ = 0.029/0.033 = 0.879


이상. Wilk's Lambda 의 값이 1의 값에 근접하고 있다. 때문에 Cmax와 AUC를 통해 뚜렷하게 목표로하는 대상을 구분하기 어렵다. 


:: 오랜만에 쓰는군... 역시나 쉽지 않아.


4. 구현 결과




Reference

[1] http://www.ijpsi.org/VOl(2)1/Version_3/G0213644.pdf

[2] http://stattrek.com/matrix-algebra/sums-of-squares.aspx


2014. 7. 29. 17:23

 Generate distinctly different RGB colors in graphs


그래프에 뚜렷한 구분을 가지는 RGB 색상 만들기 

- 머.... 그래프 작업에 필수적인 요소이지만 미뤄왔던 일이다. 오늘도 할일은 있지만 해결하고 가야겠지...돈도 안주는 일인데 하자니...땍!!!

우선 진행해 보자. 먼저 자료를 찾았다. 

http://stackoverflow.com/questions/309149/generate-distinctly-different-rgb-colors-in-graphs

위 링크를 따라가보면 이글 제목과 같이 질문을 올렸다. 


질문을 정리하면 

"아놔 랜덤으로 뚜렷하게 구분되는 RGB 색상을 어떻게 만들어??"


답변을 보면 다음과 같다. 

You have three colour channels 0 to 255 R, G and B.

너는 3개의 RGB 채널을 가지고 있어

First go through: 먼저 다음과 같이 가자

0, 0, 255
0, 255, 0
255, 0, 0

Then go through: 그리고 다음과 같이 가는거야

0, 255, 255
255, 0, 255
255, 255, 0

Then divide by 2 => 128 and start again: 그리고 2로 나누자고 ==> 128이지? 그럼 또 나눠

0, 0, 128
0, 128, 0
128, 0, 0
0, 128, 128
128, 0, 128
128, 128, 0

Divide by 2 => 64 : 자 그럼 64야 

Next time add 64 to 128 => 192 : 자 다음으로 64와 128을 더해 그럼 192잖아 

follow the pattern.위와 같은 패턴을 따라봐

Straightforward to program and gives you fairly distinct colours. ; 프로그램하는것도 간단하고, 너에게 뚜렷한 RGB 색상을 주게 될꺼얌~~~

EDIT: Request for code sample: 코드 샘플에 대한 요청(유후~~~)

Also - adding in the additional pattern as below if gray is an acceptable colour:

그레이 색상을 허용하려면 아래와 같이 추가적인 패턴을 넣어봐

255, 255, 255
128, 128, 128 

There are a number of ways you can handle generating these in code.

여기 코드에는 RGB 색상을 만들기 위해 여러가지 방법이 있다오~~

The Easy Way:: 쉬운 방법이야!!!

If you can guarantee that you will never need more than a fixed number of colours, just generate an array of colours following this pattern and use those: 그냥 배열을 만들어서 쓰셈~~!!

    static string[] ColourValues = new string[] { 
        "FF0000", "00FF00", "0000FF", "FFFF00", "FF00FF", "00FFFF", "000000", 
        "800000", "008000", "000080", "808000", "800080", "008080", "808080", 
        "C00000", "00C000", "0000C0", "C0C000", "C000C0", "00C0C0", "C0C0C0", 
        "400000", "004000", "000040", "404000", "400040", "004040", "404040", 
        "200000", "002000", "000020", "202000", "200020", "002020", "202020", 
        "600000", "006000", "000060", "606000", "600060", "006060", "606060", 
        "A00000", "00A000", "0000A0", "A0A000", "A000A0", "00A0A0", "A0A0A0", 
        "E00000", "00E000", "0000E0", "E0E000", "E000E0", "00E0E0", "E0E0E0", 
    };

The Hard Way:: 흠 좀 어렵겠군!!! +___+ 췌 

If you don't know how many colours you are going to need, the code below will generate up to 896 colours using this pattern. (896 = 256 * 7 / 2) 256 is the colour space per channel, we have 7 patterns and we stop before we get to colours separated by only 1 colour value.

얼마나 많은 RGB 컬러가 필요할지 모르지? 아래 코드는 896개의 색상을 만드는 소스 코드야~. 256은 채널당 색공간(colour space) 이야, 우리는 7개의 패턴을 가지고 있엉, 우리는 오직 1 색공간에 의해 나뉘지는  색을 가지기 전에 그만 둘것이야(먼 예기야~ 흠 아무래도 나뉘지지 않게 되면 정지 요런 느낌!!???) 소스 코드 보면 분명해지겠지 

I've probably made harder work of this code than I needed to. First, there is an intensity generator which starts at 255, then generates the values as per the pattern described above. The pattern generator just loops through the seven colour patterns.

나도 이게 필요해서 열심히 만들었어. 처음, intensity generator(255에서 시작하는)가 있어, 그리고 위에 묘사된 패턴별로 값들을 만들엉. 패턴 발생기는 7개의 패턴을 따라 루프를 도는거만 하징..

아놔 C# 이넹 난 C/C++ 코드가 필요한뎅 ㅠㅠ 으아앙

할 수 없지... 변환해서 써보자 

using System;

class Program {
    static void Main(string[] args) {
        ColourGenerator generator = new ColourGenerator();
        for (int i = 0; i < 896; i++) {
            Console.WriteLine(string.Format("{0}: {1}", i, generator.NextColour()));
        }
    }
}

public class ColourGenerator {

    private int index = 0;
    private IntensityGenerator intensityGenerator = new IntensityGenerator();

    public string NextColour() {
        string colour = string.Format(PatternGenerator.NextPattern(index),
            intensityGenerator.NextIntensity(index));
        index++;
        return colour;
    }
}

public class PatternGenerator {
    public static string NextPattern(int index) {
        switch (index % 7) {
        case 0: return "{0}0000";
        case 1: return "00{0}00";
        case 2: return "0000{0}";
        case 3: return "{0}{0}00";
        case 4: return "{0}00{0}";
        case 5: return "00{0}{0}";
        case 6: return "{0}{0}{0}";
        default: throw new Exception("Math error");
        }
    }
}

public class IntensityGenerator {
    private IntensityValueWalker walker;
    private int current;

    public string NextIntensity(int index) {
        if (index == 0) {
            current = 255;
        }
        else if (index % 7 == 0) {
            if (walker == null) {
                walker = new IntensityValueWalker();
            }
            else {
                walker.MoveNext();
            }
            current = walker.Current.Value;
        }
        string currentText = current.ToString("X");
        if (currentText.Length == 1) currentText = "0" + currentText;
        return currentText;
    }
}

public class IntensityValue {

    private IntensityValue mChildA;
    private IntensityValue mChildB;

    public IntensityValue(IntensityValue parent, int value, int level) {
        if (level > 7) throw new Exception("There are no more colours left");
        Value = value;
        Parent = parent;
        Level = level;
    }

    public int Level { get; set; }
    public int Value { get; set; }
    public IntensityValue Parent { get; set; }

    public IntensityValue ChildA {
        get {
            return mChildA ?? (mChildA = new IntensityValue(this, this.Value - (1<<(7-Level)), Level+1));
        }
    }

    public IntensityValue ChildB {
        get {
            return mChildB ?? (mChildB = new IntensityValue(this, Value + (1<<(7-Level)), Level+1));
        }
    }
}

public class IntensityValueWalker {

    public IntensityValueWalker() {
        Current = new IntensityValue(null, 1<<7, 1);
    }

    public IntensityValue Current { get; set; }

    public void MoveNext() {
        if (Current.Parent == null) {
            Current = Current.ChildA;
        }
        else if (Current.Parent.ChildA == Current) {
            Current = Current.Parent.ChildB;
        }
        else {
            int levelsUp = 1;
            Current = Current.Parent;
            while (Current.Parent != null && Current == Current.Parent.ChildB) {
                Current = Current.Parent;
                levelsUp++;
            }
            if (Current.Parent != null) {
                Current = Current.Parent.ChildB;
            }
            else {
                levelsUp++;
            }
            for (int i = 0; i < levelsUp; i++) {
                Current = Current.ChildA;
            }

        }
    }
}





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace RandomDistinctlyRGB
{
    class Program
    {
        static void Main(string[] args)
        {
            ColourGenerator generator = new ColourGenerator();
            for (int i = 0; i < 896; i++)
            {
                Console.WriteLine(string.Format("{0}: {1}", i, generator.NextColour()));
            }
        }
    }
    public class ColourGenerator
    {
 
        private int index = 0;
        private IntensityGenerator intensityGenerator = new IntensityGenerator();
 
        public string NextColour()
        {
            string colour = string.Format(PatternGenerator.NextPattern(index),
                intensityGenerator.NextIntensity(index));
            index++;
            return colour;
        }
    }
 
    public class PatternGenerator
    {
        public static string NextPattern(int index)
        {
            switch (index % 7)
            {
                case 0: return "{0}0000";
                case 1: return "00{0}00";
                case 2: return "0000{0}";
                case 3: return "{0}{0}00";
                case 4: return "{0}00{0}";
                case 5: return "00{0}{0}";
                case 6: return "{0}{0}{0}";
                defaultthrow new Exception("Math error");
            }
        }
    }
 
    public class IntensityGenerator
    {
        private IntensityValueWalker walker;
        private int current;
 
        public string NextIntensity(int index)
        {
            if (index == 0)
            {
                current = 255;
            }
            else if (index % 7 == 0)
            {
                if (walker == null)
                {
                    walker = new IntensityValueWalker();
                }
                else
                {
                    walker.MoveNext();
                }
                current = walker.Current.Value;
            }
            string currentText = current.ToString("X");
            if (currentText.Length == 1) currentText = "0" + currentText;
            return currentText;
        }
    }
 
    public class IntensityValue
    {
 
        private IntensityValue mChildA;
        private IntensityValue mChildB;
 
        public IntensityValue(IntensityValue parent, int value, int level)
        {
            if (level > 7) throw new Exception("There are no more colours left");
            Value = value;
            Parent = parent;
            Level = level;
        }
 
        public int Level { get; set; }
        public int Value { get; set; }
        public IntensityValue Parent { get; set; }
 
        public IntensityValue ChildA
        {
            get
            {
                return mChildA ?? (mChildA = new IntensityValue(thisthis.Value - (1 << (7 - Level)), Level + 1));
            }
        }
 
        public IntensityValue ChildB
        {
            get
            {
                return mChildB ?? (mChildB = new IntensityValue(this, Value + (1 << (7 - Level)), Level + 1));
            }
        }
    }
 
    public class IntensityValueWalker
    {
 
        public IntensityValueWalker()
        {
            Current = new IntensityValue(null, 1 << 7, 1);
        }
 
        public IntensityValue Current { get; set; }
 
        public void MoveNext()
        {
            if (Current.Parent == null)
            {
                Current = Current.ChildA;
            }
            else if (Current.Parent.ChildA == Current)
            {
                Current = Current.Parent.ChildB;
            }
            else
            {
                int levelsUp = 1;
                Current = Current.Parent;
                while (Current.Parent != null && Current == Current.Parent.ChildB)
                {
                    Current = Current.Parent;
                    levelsUp++;
                }
                if (Current.Parent != null)
                {
                    Current = Current.Parent.ChildB;
                }
                else
                {
                    levelsUp++;
                }
                for (int i = 0; i < levelsUp; i++)
                {
                    Current = Current.ChildA;
                }
 
            }
        }
    }
}
 










'Tips' 카테고리의 다른 글

Tip: Scaling a range of numbers with a known min and max value  (0) 2014.05.25