在工作上有使用到Quantile normalization的統計,不過在這邊不是要說明這個統計的意義,而
是說明如何利用Java來實作。至於要理解他的概念可以至Wiki。
假設有一個二維陣列如下:
一、排序處理
在這邊由於我們要去排序3個column的資料,分別為23,10,44,88 ; 54,84,90,12 ; 95,61,36,63
,而一般陣列在讀取時,比較好讀的順序是23, 54, 95,如此我們可以先將此陣列做
transpose的動作,將exp[3][4] => exp[4][3]
二、做平均,並更換值
依據Quantile的說明,這exp[3][4] 需要針對排序後的資料去做一個row一個row的平均,
排序後需為:
再來是算出來的平均去替換排序後同一個row的值,如10,12,36需替還成19.33,以此類推。
三、回復排序前的位置
最後經由平均去替換值,還需要將值回復成原來的位置,如原本[0][0] = 23,23後來是排在
[0][1]且值變成了46,因此[0][0] = 46,以此類推。回復位置後的array如下:
這就是最後的結果。
好,上面說完了大概的流程,回歸程式的部分,撇開目視的類推,在這邊我們會先
做transpose,如下:
如此將得到3x4
再來我們將針對排序的議題,利用Arrays.sort幫我們輕鬆做到,但我們需要去定義
一個Comparator interface(規則),並且將陣列內的值存進另外定義的class Quantile,此類別有
兩個欄位,分別是存值及位置(此位置為transpose後的陣列位置)
Comparator interface (compare的部分就不細部說明,在此篇有特別提到)
Quantile Class如下
這個n_exp的二維物件陣列,除了擁有值且具有position的部分。
首先我們利用Arrays.sort進行值的排序,並且計算average,如下:
請注意由於我們將array做了transpose,因此我們要計算的average是看column的部分
在來是做值的替換,如下:
轉換後,如下
再來是透過position的排序,值回復原來的位置
回復後,如下:
最後就是將二維物件陣列的值assign給exp2 array,並且transpose回原來的array
再來是print new_exp得到,
如此就大功告成囉!篇幅有點冗長,若有弄錯的地方請不吝指正!
是說明如何利用Java來實作。至於要理解他的概念可以至Wiki。
假設有一個二維陣列如下:
double exp[][] = {{23,54,95},
{10,84,61},
{44,90,36},
{88,12,63}};
一、排序處理
在這邊由於我們要去排序3個column的資料,分別為23,10,44,88 ; 54,84,90,12 ; 95,61,36,63
,而一般陣列在讀取時,比較好讀的順序是23, 54, 95,如此我們可以先將此陣列做
transpose的動作,將exp[3][4] => exp[4][3]
二、做平均,並更換值
依據Quantile的說明,這exp[3][4] 需要針對排序後的資料去做一個row一個row的平均,
排序後需為:
23,54,95 10,12,36 => average (19.3) 10,84,61 23,54,61 => average (46.0) => 44,90,36 44,84,63 => average (63.7) 88,12,63 88,90,95 => average (91.0)
再來是算出來的平均去替換排序後同一個row的值,如10,12,36需替還成19.33,以此類推。
19.3,19.3,19.3 46.0,46.0,46.0 63.7,63.7,63.7 91.0,91.0,91.0
三、回復排序前的位置
最後經由平均去替換值,還需要將值回復成原來的位置,如原本[0][0] = 23,23後來是排在
[0][1]且值變成了46,因此[0][0] = 46,以此類推。回復位置後的array如下:
46.0,46.0,91.0 19.3,63.7,46.0 63.7,91.0,19.3 91.0,19.3,63.7
這就是最後的結果。
好,上面說完了大概的流程,回歸程式的部分,撇開目視的類推,在這邊我們會先
做transpose,如下:
public static double[][] transpose(double exp[][]){
double trans[][] = new double[exp[0].length][exp.length];
for(int j = 0 ; j < exp[0].length ; j++){
for(int i = 0 ; i < exp.length ; i++){
trans[j][i] = exp[i][j];
}
}
return trans;
}
如此將得到3x4
23,10,44,88 54,84,90,12 95,61,36,63
再來我們將針對排序的議題,利用Arrays.sort幫我們輕鬆做到,但我們需要去定義
一個Comparator interface(規則),並且將陣列內的值存進另外定義的class Quantile,此類別有
兩個欄位,分別是存值及位置(此位置為transpose後的陣列位置)
double exp2[][] = transpose(exp);
Quantile n_exp[][] = new Quantile[exp2.length][exp2[0].length];
for(int i = 0 ; i < exp2.length ; i++){
for(int j = 0 ; j < exp2[0].length ; j++){
n_exp[i][j] = new Quantile(j, exp2[i][j]);
}
}
Comparator interface (compare的部分就不細部說明,在此篇有特別提到)
class QuanCompare implements Comparator{
private String methodName;
public QuanCompare(String methodName){
this.methodName = methodName;
}
@Override
public int compare(Quantile o1, Quantile o2) {
// TODO Auto-generated method stub
try{
Method method1 = o1.getClass().getDeclaredMethod(this.methodName);
Method method2 = o2.getClass().getDeclaredMethod(this.methodName);
Object obj1 = method1.invoke(o1);
Object obj2 = method2.invoke(o2);
if(methodName.equals("getExpvalue")){
if((double)obj1 > (double)obj2){
return 1;
}else{
return -1;
}
}else{
if((int)obj1 > (int)obj2){
return 1;
}else{
return -1;
}
}
}catch(Exception e){
e.printStackTrace();
}
return 0;
}
}
Quantile Class如下
class Quantile{
private int pos;
private double expvalue;
public Quantile(int pos, double expvalue) {
super();
this.pos = pos;
this.expvalue = expvalue;
}
public int getPos() {
return pos;
}
public double getExpvalue() {
return expvalue;
}
public void setPos(int pos) {
this.pos = pos;
}
public void setExpvalue(double expvalue) {
this.expvalue = expvalue;
}
}
這個n_exp的二維物件陣列,除了擁有值且具有position的部分。
首先我們利用Arrays.sort進行值的排序,並且計算average,如下:
double avg[] = new double[exp.length];
for(int i = 0 ; i < exp2.length ; i++){
Arrays.sort(n_exp[i], new QuanCompare("getExpvalue"));
for(Quantile t : n_exp[i]){
avg[x] = avg[x]+t.getExpvalue();
if(i == exp2.length-1){
avg[x] = avg[x]/exp2.length;
}
x++;
}
x = 0;
}
請注意由於我們將array做了transpose,因此我們要計算的average是看column的部分
10,23,44,88 12,54,84,90 36,61,63,95
在來是做值的替換,如下:
for(int i = 0 ; i < exp2.length ; i++){
for(Quantile t : n_exp[i]){
t.setExpvalue(avg[x]);
x++;
}
x = 0;
}
轉換後,如下
19.3,46.0,63.7,91.0 19.3,46.0,63.7,91.0 19.3,46.0,63.7,91.0
再來是透過position的排序,值回復原來的位置
for(int i = 0 ; i < exp2.length ; i++){
Arrays.sort(n_exp[i], new QuanCompare("getPos"));
}
回復後,如下:
46.0,19.3,63.7,91.0 46.0,63.7,91.0,19.3 91.0,46.0,19.3,63.7
最後就是將二維物件陣列的值assign給exp2 array,並且transpose回原來的array
for(int i = 0 ; i < exp2.length ; i++){
for(Quantile t : n_exp[i]){
exp2[i][x] = t.getExpvalue();
x++;
}
x = 0;
}
double new_exp[][] = transpose(exp2);
再來是print new_exp得到,
46.0,46.0,91.0 19.3,63.7,46.0 63.7,91.0,19.3 91.0,19.3,63.7
如此就大功告成囉!篇幅有點冗長,若有弄錯的地方請不吝指正!
留言
張貼留言