Personnummer

Personnummer atau Personal Identification Number adalah nomor tunggal pengenal identitas diri yang dipakai di Swedia atau istilah kerennya Single Identity Number. Nomor ini dipakai untuk data kependudukan dan digunakan untuk berbagai keperluan seperti sekolah, bank, dan asuransi. Saya pernah diberi tahu kalau bedanya personnummer dengan nomor KTP di Indonesia adalah kalau personnummer kita pasti ingat nomornya sedangkan nomor KTP kita tidak pernah ingat. Ini bisa jadi indikasi bahwa personnummer itu tingkat ke-penting-an-nya sangat tinggi sehingga kita memang butuh mengingatnya karena penggunaannya yang masif, terstruktur, dan sistematis pada kehidupan sehari-hari. Atau memang karena nomornya lebih pendek dari nomor KTP.

Penjelasan lebih dalam dan teknis mengenai personnummer bisa dilihat pada presentasi di bawah.

Untuk kegunaan personnummer yang digunakan dalam riset bisa dilihat di slide presentasi di bawah.

Untuk mendaftar personnummer bagi kaum pendatang, kita harus datang ke kantor pajak atau skatteverket dengan membawa passport, residence permit, dan bukti tinggal di Swedia lebih dari 1 tahun (notification of selection untuk student). Nah, syarat terakhir ini yang membuat agak ‘tricky’ untuk mendapat personnummer. Salah satu kisah nyata perjuangan untuk mendapatkan personnummer bisa dibaca di sini: http://fajriahnur.wordpress.com/2014/05/18/cerita-daftar-personnummer/

skatteverket

Lokasi kantor skatteverket yang ada di sekitar Stockholm

Keuntungan memiliki personnummer cukup beragam, seperti (konon) biaya kesehatan yang jauh lebih murah. Yang ini saya belum bisa buktikan karena Alhamdulillah saya belum pernah ke dokter. Sekarang saya akan cerita tentang kegunaan personnummer yang pernah saya gunakan selain untuk buka akun bank.

1. Kartu SL

Transportasi dalam kota Stockholm yang terdiri dari bis, metro (tunnelbana), commuter rails (pendeltag), dan kapal, semuanya menggunakan kartu SL. Kartu SL ini bisa dibeli di minimarket seperti pressbyran atau SL center yang terdapat di beberapa stasiun tunnelbana dengan harga 20 SEK. Setelah dibeli, kartu SL bisa diisi dengan uang (reskasssa/travel fund) untuk melakukan pembayaran pada setiap kali perjalanan. Untuk perjalanan pada satu zona yang sama dikenakan biaya sebesar 2 kupon atau 25 SEK (1 kupon 12.5 SEK). Jika melewati zona yang berbeda maka biayanya 3 kupon dan jika dari zona A ke C atau sebaliknya dikenakan 4 kupon. Masuk ke daerah lain seperti Uppsala, dikenakan tiket tambahan lagi.

sl card

Kartu SL keren

Alternatif lain selain menggunakan travel fund adalah membeli periodbiljett atau season ticket (atau tiket abodemen kalau bahasa KRL jabodetabek jaman dulu). Tiket dimulai dari 115 SEK untuk 24 jam, 230 SEK untuk 72 jam, 300 SEK untuk 1 minggu, 790 SEK untuk 1 bulan, dan 2300 SEK untuk 3 bulan, Pelajar mendapat diskon untuk tiket 1 bulan menjadi hanya 560 SEK dan tiket 3 bulan menjadi 1540 SEK. Season ticket dan travel fund bisa diisi ditempat kartu tersebut dibeli atau di mesin tiket yang tersedia di semua stasiun tunnelbana.

ticket machine

Mesin untuk membeli tiket yang di-load ke dalam kartu SL. Pembayaran bisa menggunakan kartu dengan logo Visa atau Maestro.

zone map

Peta moda transportasi yang dibagi menjadi Zona A, B, dan C. Kalau menggunakan tiket bulanan sih tidak perlu pusing memikirkan apakah daerah tujuannya termasuk zona yang mana.

Nah, kalau misalkan kita sudah beli tiket SL kemudian diisi tiket untuk perjalanan selama 3 bulan. Kemudian kartu tersebut hilang setelah baru dipakai hanya 1 hari, wah kalau saya pasti nangis darah. Agar amannya, kartu SL bisa didaftarkan di website SL, tentunya dengan menggunakan personnummer.

Buka website sl.se kemudian pilih menu Mitt SL.

sl.se

Daftar akun baru dengan mengklik skapa konto kemudian mengisi data diri dengan benar (jangan lupa personnummer-nya).

create account

Setelah itu seharusnya ada email dari SL yang berisi kode aktivasi. Masukkan.

activate account

Setelah itu Anda bisa log-in dengan username dan password yang sudah diisi tadi.

login

Registrasi kartu Anda dengan memasukkan 10 digit kode angka yang ada di belakang kartu SL. Kasih nama juga yang bagus.

sl card back

register card

Kartu yang sudah didaftarkan akan terlihat di atas beserta isi tiket yang ada di dalamnya. Kita bisa mendaftarkan lebih dari satu kartu ke dalam sistem.

list card

Jika kartu Anda hilang, jangan panik. Klik kartu yang hilang tersebut di menu atas dan pilih Forlustanmal kort untuk memblok kartu yang hilang plus mengirimkan kartu baru ke alamat rumah kita. Loh, tahu dari mana dia alamat rumah kita? Tentunya dari nomor personnummer yang kita gunakan. Berdasarkan pengalaman saya pribadi, kartu baru sampai ke kediaman rumah dalam waktu 3 hari. Enak kan…

block card

2. Kartu Perpustakaan

Setelah kita memiliki personnummer, kita dapat membuat kartu perpustakaan secara gratis, tanpa biaya apapun, agar bisa meminjam pada lebih dari 40 perpustakaan yang tersebar di seluruh penjuru Stockholm. Jumlah buku yang bisa dipinjam dalam satu waktu adalah 50 buku. Lama waktu peminjaman adalah sekitar 4 minggu yang bisa diperpanjang sebanyak 2 kali (kecuali bukunya sudah direservasi orang lain), bisa menggunakan mesin yang sama untuk meminjam buku atau diperpanjang secara online. Buku yang sudah dipinjam dapat dikembalikan di perpus manapun yang Anda mau. Agar tidak repot mencari bukunya (kecuali Anda petualang yang senang menemukan buku-buku menarik tak terduga) di rak-rak yang jumlah banyak, Anda bisa melakukan reservasi buku secara online dengan biaya hanya 10 SEK.

Koleksi buku apa saja yang ada di perpus dapat dilihat di website https://biblioteket.stockholm.se/

biblioteket.se

Untuk mendapatkan kartu perpus, pertama kita harus registrasi secara online di https://biblioteket.stockholm.se/en/user/register

register library

Kemudian datangi perpus terdekat dan minta kartu Anda pada bagian informasi. Jika sudah maka Anda akan mendapat kartu perpus keren seperti ini. Gampang kan…

library card

Kartu perpus keren.

Ini contoh buku yang saat tulisan ini dibuat sedang dipinjam.

books

Dari kiri atas ke kanan bawah. I, Robot oleh Isaac Asimov; Flatland oleh Edwin Abbott; Time Machine oleh H.G. Wells; Black Jack oleh Osamu Tezuka; dan Time Out of Joint oleh Philip K. Dick

Semoga berguna. Salam.

Visualisasi dengan Processing

Pada post ini saya akan memperkenalkan processing. Processing adalah bahasa pemrograman yang digunakan untuk membuat visualisasi dalam bentuk gambar statis dan/atau animasi. Secara bahasa pemrograman, Processing memiliki sintaks yang mirip dengan Java.

logo

Instalasi

Masuk ke halaman Download di situs processing dan pilih file sesuai dengan sistem operasi yang Anda gunakan.

download

Ekstrak file zip ke direktori manapun yang dikehendaki.

Getting Started

Buka folder hasil ekstraksi dan jalankan processing.exe

processing

Gambar di atas adalah tampilan awal dari processing ketika baru dijalankan. Pada text editor, ketikkan kode berikut untuk menginisialisasi visualisasi baru lalu klik tombol Rum (yang gambar segitiga) atau lewat menu Sketch > Run atau dengan shortcut Ctrl+R.

void setup() {
  size(500, 400);
}

void draw() {
  background(0,0,255);
}

Seharusnya keluar window baru dengan warna latar belakang biru. Kode di atas merupakan kode paling dasar pada Processing. fungsi setup() dijalankan sekali pada waktu program mulai berjalan di awal sedangkan fungsi draw() dipanggil berulang kali dalam satu detik. Berapa kali fungsi draw() dipanggil bisa dikontrol dengan fungsi frameRate() di mana nilai standarnya adalah 60 fps.

Contoh: Bacteria random walk

Untuk contoh yang sedikit lebih rumit dibanding hanya background kosong, kita akan membuat animasi bakteri yang berjalan secara acak.
Pertama, kita buat kelas baru untuk menyimpan data posisi bakteri. Jangan lupa fungsi constructor untuk menginisialisasi posisi awal bakteri.

class Bactery {
  int x;
  int y;
  float angle;
  
  Bactery() {
    x = int(random(width));
    y = int(random(height));
    angle = 2*PI*random(1);
  }
  
  Bactery(int x, int y) {
    this.x = x;
    this.y = y;
    angle = 0;
  }
}

Kemudian kita tambahkan fungsi display() untuk menggambar bakteri, dimana kita sederhanakan bentuk bakteri menjadi sebuah segi empat.

void display() {
    stroke(0);
    fill(0);
    
    if(random(1) < 0.2)
      angle = 2*PI*random(1);
      
    int x1 = bactWidth;
    int y1 = 0;
    
    int x2 = bactWidth;
    int y2 = bactHeight;
    
    int x3 = 0;
    int y3 = bactHeight;
    
    // Apply the rotation
    int nx1 = int( x1*cos(angle) - y1*sin(angle) +x);
    int ny1 = int( x1*sin(angle) + y1*cos(angle) +y);
    
    int nx2 = int( x2*cos(angle) - y2*sin(angle) +x);
    int ny2 = int( x2*sin(angle) + y2*cos(angle) +y);
    
    int nx3 = int( x3*cos(angle) - y3*sin(angle) +x);
    int ny3 = int( x3*sin(angle) + y3*cos(angle) +y);
    
    quad(x, y, nx1, ny1, nx2, ny2, nx3, ny3);
  }

Tambahkan pula fungsi step() untuk meng-update posisi bakteri pada setiap frame.

void step() {
    int moveX = int(random(11)) - 5;
    int moveY = int(random(11)) - 5;
    
    x += moveX;
    y += moveY;
  }

Instansiasi objek bakteri di awal, kemudian kita panggil kedua fungsi diatas pada setiap frame.

void setup() {
  size(500, 400);
  
  bacteria = new Bactery[numBact];
  for(int i=0; i<numBact; i++) {
    bacteria[i] = new Bactery();
  }
}

void draw() {
  background(255,255,255);
  
  for(int i=0; i<numBact; i++) {
    bacteria[i].step();
    bacteria[i].display();
  }
}

Jangan lupa untuk menambahkan variabel-variabel global yang dipakai.

Bactery[] bacteria;
int numBact = 200;
int bactWidth = 2;
int bactHeight = 10;

Contoh tampilan ketika dijalankan: bakteri yang jumlahnya banyak menggeliat sepanjang waktu.

bakteri

Processing on the Web

dengan menggunakan processing.js, program processing Anda akan secara ajaib dan otomatis bisa ditampilkan pada halaman web dengan memanfaatkan teknologi HTML5. Cukup dengan membuat sebuah halaman html kosong, import processingjs, dan tambahkan canvas ke dalamnya.

<script src="https://raw.github.com/processing-js/processing-js/v1.4.8/processing.min.js"></script>
<canvas data-processing-sources="bacterium.pde"></canvas>

Karena wordpress.com tidak bisa pakai iframe, maka animasinya bisa dilihat pada link berikut: http://mitbal.com/bacterium.html

Seperti biasa kode lengkap bisa dilihat di repository github: https://github.com/mitbal/pro-bacterium

Demikian, semoga berguna. Sampai ketemu pada contoh-contoh visualisasi lainnya.
Salam.

Baseline Wander Removal dengan Wavelet

Pada post kali ini, kita akan melakukan proses menghilangkan baseline wander (baseline wander removal) pada sinyal EKG dengan menggunakan transformasi wavelet seperti yang ditulis oleh Sargolzaei et al pada paper dengan judul “A new robust wavelet based algorithm for baseline wandering cancellation in ECG signals“.

Latar belakang
Elektrokardiogram (EKG) adalah pembacaan sinyal elektrik jantung dengan cara menempelkan elektroda ke posisi tertentu pada tubuh dan kemudian membaca nilai perbedaan potensial listrik alias tegangan yang dihasilkan. Dari pembacaan ini kita bisa mencari tahu mengenai kondisi jantung. Akan tetapi, sinyal yang baru dibaca ini tidak lepas dari noise sehingga bisa mengganggu proses diagnosis. Sumber noise ini berasal dari berbagai macam, seperti elektroda dari elektroda itu sendiri atau jika tubuh bergerak ketika dilakukan pengukuran. Salah satu kondisi noise yang sering menyerang adalah situasi yang disebut baseline wander. Baseline wander terjadi apabila sinyal EKG tidak lurus pada sumbu x, malah naik turun. Contoh bisa dilihat di gambar 1.

bwr

Contoh sinyal yang terkena baseline wander dan hasilnya setelah dihilangkan. Gambar diambil tanpa izin dari paper yang dirujuk di atas.

Baseline wander removal (BWR) adalah salah satu tahap preprocessing pada sinyal EKG untuk menghilangkan baseline drift ini. Ada beberapa teknik yang bisa dipakai, seperti melakukan filtering. Pada post ini, kita akan mengimplementasikan salah satu teknik yang memanfaatkan transformasi wavelet. Penjelasan dasar mengenai wavelet salah satunya bisa dilihat di http://users.rowan.edu/~polikar/WAVELETS/WTtutorial.html. Kelebihan dari teknik ini adalah kita tidak perlu menentukan parameter seperti ketika menggunakan high pass filter (frequency cut-off) sehingga metode kita bekerja secara non-supervised.

Sinyal EKG yang sudah bersih dari noise semacam ini kemudian bisa digunakan untuk berbagai macam kegunaan. Untuk pembahasan mengenai kegunaan sinyal EKG untuk mengenali tipe detak arrhythmia atau diagnosis tahapan tidur, bisa merujuk ke paper ini dan ini.

Algoritma
Berikut adalah tahapan dalam algoritma ini. Pertama, kita lakukan dekomposisi kepada sinyal asli dengan transformasi wavelet. Dalam hal ini kita memilih Daubechies orde 4 sebagai fungsi basisnya. Sinyal didekomposisi menjadi bagian frekuensi rendah/aproksimasi dan frekuensi tinggi/detail. Kemudian kita hitung nilai energi pada sinyal frekuensi tinggi. Kita cari kondisi dimana nilai energi pada level dekomposisi tersebut lebih rendah dari pada nilai pada level dekomposisi sebelumnya dan sesudahnya (alias lokal minima). Setelah kita temukan level tersebut, kita rekonstruksi sinyal aproksimasi dari level ini dengan membuang nilai pada sinyal frekuensi tinggi (atau dijadikan 0 semua). Sinyal hasil rekonstruksi ini kita sebut dengan baseline. Untuk menghilangkan baseline wander pada sinyal asli, maka kita kurangkan sinyal asli dengan sinyal baseline.

level

Gambar atas: plot nilai energi pada sinyal detail pada berbagai level dekomposisi. Tanda panah menunjukkan level ketika nilainya adalah lokal minima. Gambar bawah: Sinyal asli, baseline, dan sinyal asli yang sudah dikurang baseline. Lagi-lagi diambil dari paper rujukan di atas.

 

Implementasi
Pertama, kita implementasi metode konvolusi antara dua sinyal.

def conv(x, h):
    """ Perform the convolution operation between two input signals. The output signal length
    is the sum of the lenght of both input signal minus 1."""
    length = len(x) + len(h) - 1
    y = [0]*length

    for i in xrange(len(y)):
        for j in xrange(len(h)):
            if i-j >= 0 and i-j < len(x):
                y[i] += h[j] * x[i-j]

    return y

Lalu kita implementasi metode dekomposisi wavelet dan jangan lupa deklarasi koefisien basis fungsi yang dipakai. Dalam kasus ini adalah Daubechies dengan 4 koefisien. Dekomposisi dilakukan dengan cara mengkonvolusi sinyal asli dengan koefisien low pass and high pass. Sinyal keluaran dari proses ini kemudian di-downsampling menjadi setengahnya dengan cara hanya mengambil nilai pada posisi ganjil atau genap saja. Hal ini dilakukan berulang terhadap sinyal keluaran low pass (atau disebut aproksimasi) sebanyak parameter level.

c0 = (1+sqrt(3))/(4*sqrt(2))
c1 = (3+sqrt(3))/(4*sqrt(2))
c2 = (3-sqrt(3))/(4*sqrt(2))
c3 = (1-sqrt(3))/(4*sqrt(2))

def db4_dec(x, level):
""" Perform the wavelet decomposition to signal x with Daubechies order 4 basis function as many as specified level"""

    # Decomposition coefficient for low pass and high pass
    lpk = [c0, c1, c2, c3]
    hpk = [c3, -c2, c1, -c0]

    result = [[]]*(level+1)
    x_temp = x[:]
    for i in xrange(level):
        lp = conv(x_temp, lpk)
        hp = conv(x_temp, hpk)

        # Downsample both output by half
        lp_ds=[0]*(len(lp)/2)
        hp_ds=[0]*(len(hp)/2)
        for j in xrange(len(lp_ds)):
            lp_ds[j] = lp[2*j+1]
            hp_ds[j] = hp[2*j+1]

        result[level-i] = hp_ds
        x_temp = lp_ds[:]

    result[0] = lp_ds
    return result

Fungsi rekontruksi digunakan untuk mencari baseline dari sinyal asal. Rekonstruksi bekerja dengan melakukan konvolusi dengan koefisien rekonstruksi pada kedua sinyal low pass dan high pass, melakukan upsampling dengan menyelipkan 0 di setiap nilai pada sinyal dan kemudian masing-masing posisi pada sinyal saling dijumlahkan.

def db4_rec(signals, level):
    """ Perform reconstruction from a set of decomposed low pass and high pass signals as deep as specified level"""

    # Reconstruction coefficient
    lpk = [c3, c2, c1, c0]
    hpk = [-c0, c1, -c2, c3]

    cp_sig = signals[:]
    for i in xrange(level):
        lp = cp_sig[0]
        hp = cp_sig[1]

        # Verify new length
        length = 0
        if len(lp) > len(hp):
            length = 2*len(hp)
        else:
            length = 2*len(lp)

        # Upsampling by 2
        lpu = [0]*(length+1)
        hpu = [0]*(length+1)
        index = 0
        for j in xrange(length+1):
            if j%2 != 0:
                lpu[j] = lp[index]
                hpu[j] = hp[index]
                index += 1

        # Convolve with reconstruction coefficient
        lpc = conv(lpu, lpk)
        hpc = conv(hpu, hpk)

        # Truncate the convolved output by the length of filter kernel minus 1 at both end of the signal
        lpt = lpc[3:-3]
        hpt = hpc[3:-3]

        # Add both signals
        org = [0]*len(lpt)
        for j in xrange(len(org)):
            org[j] = lpt[j] + hpt[j]

        if len(cp_sig) > 2:
            cp_sig = [org]+cp_sig[2:]
        else:
            cp_sig = [org]

    return cp_sig[0]

Method calcEnergy menghitung nilai energi dari sebuah sinyal berdasarkan definisinya yaitu jumlahan kuadrat sinyal di tiap titik

def calcEnergy(x):
    """ Calculate the energy of a signal which is the sum of square of each points in the signal."""
    total = 0
    for i in x:
        total += i*i
    return total

Kemudian method bwr berikut adalah implementasi dari algoritma yang dijabarkan di atas.

def bwr(raw):
    """ Perform the baseline wander removal process against signal raw. The output of this method is signal with correct baseline
    and its baseline """
    en0 = 0
    en1 = 0
    en2 = 0
    n = 0

    curlp = raw[:]
    num_dec = 0
    last_lp = []
    while True:
        print 'Iterasi ke' + str(num_dec+1)
        print len(curlp)

        # Decompose 1 level
        [lp, hp] = db4_dec(curlp,1)

        # Shift and calculate the energy of detail/high pass coefficient
        en0 = en1
        en1 = en2
        en2 = calcEnergy(hp)
        print en2

        # Check if we are in the local minimum of energy function of high-pass signal
        if en0 > en1 and en1 < en2:
            last_lp = curlp
            break

        curlp = lp[:]
        num_dec = num_dec+1

    # Reconstruct the baseline from this level low pass signal up to the original length
    base = last_lp[:]
    for i in xrange(num_dec):
        base = db4_rec([base,[0]*len(base)], 1)

    # Correct the original signal by subtract it with its baseline
    ecg_out = [0]*len(raw)
    for i in xrange(len(raw)):
        ecg_out[i] =  raw[i] - base[i]

    return (base, ecg_out)

Contoh
Untuk contoh kita ambil data dari situs Physionet khususnya MIT-BIH Arrhythmia database. Data diambil dari salah satu record pasien dengan kode nomor 101. Sinyal EKG diambil sepanjang 1 menit. Sinyal EKG yang diambil berasal dari lead II dan V5.

Contoh kode untuk memanggil modul dan fungsi yang sudah dibuat di atas adalah sebagai berikut

import bwr
import matplotlib.pyplot as plt

# Read input csv file from physionet
f = open('samples1.csv', 'r')
lines = f.readlines()
f.close()

# Discard the first two lines because of header. Takes either column 1 or 2 from each lines (different signal lead)
signal = [0]*(len(lines)-2)
for i in xrange(len(signal)):
	signal[i] = float(lines[i+2].split(',')[1])

# Call the BWR method
(baseline, ecg_out) = bwr.bwr(signal)

plt.subplot(2,1,1)
plt.plot(signal, 'b-')
plt.plot(baseline, 'r-')

plt.subplot(2,1,2)
plt.plot(ecg_out, 'b-')
plt.show()

Berikut contoh pertama. Garis merah pada plot merupakan baseline dari sinyal EKG.

samples1

Berikut adalah contoh kedua.

samples2

Contoh berikut diambil dari lead V5.

samples3

Kode lengkap dan sampel sinyal dapat dilihat di: https://github.com/mitbal/py-bwr

Semoga berguna. Salam.

UPGMA

Pada post kali ini kita akan mengimplementasi algoritma UPGMA atau Unweighted Pair Group Method with Arithmetic Mean untuk melakukan clustering.

Algoritma
UPGMA bekerja dengan prinsip yang sederhana. Pada setiap iterasi, pilih pasangan point dengan point, atau point dengan cluster, atau cluster dengan cluster, yang memiliki jarak yang terpendek. Gabung kedua pasangan ini kedalam satu cluster. Hal ini dilakukan terus menerus hingga jumlah cluster berkurang menjadi jumlah yang diinginkan. Untuk menghitung jarak antar datapoint, kita bisa menggunakan berbagai kriteria jarak. Pada implementasi ini, kita menggunakan euclidean distance untuk menghitung jarak. Sedangkan untuk menghitung jarak antar cluster, kita hitung dengan cara merata-ratakan jarak antar semua pasang point dari cluster pertama ke cluster kedua, atau dengan kata lain:

\frac{1}{|A|.|B|} \sum_{x \in A} \sum_{y \in B} d(x,y)

Teknik UPGMA ini bisa digolongkan kepada teknik hierarchical clustering karena kita bisa melihat hirarki sebuah cluster yang dibentuk dari cluster-cluster lain yang lebih kecil.

Implementasi
Kita implementasikan UPGMA dalam bahasa Python. Pertama, kita butuh struktur data untuk menyimpan point yang terdapat pada sebuah cluster.

class Node:
    def __init__(self, p):
        self.points = p
        self.right = None
        self.left = None

Fungsi UPGMA menerima dua parameter. Parameter pertama adalah set yang berisi datapoints sebanyak n dengan masing-masing point memiliki dimensi d. Parameter kedua adalah jumlah cluster yang kita inginkan.

def upgma(points, k):
    """ Cluster based on distance matrix dist using Unweighted Pair Group Method with Arithmetic Mean algorithm up to k cluster"""

    # Initialize each cluster with one point
    nodes = []
    n = len(points)
    for i in xrange(n):
        node = Node([points[i]])
        nodes = nodes + [node]

    # Iterate until the number of clusters is k
    nc = n
    while nc > k:
        # Calculate the pairwise distance of each cluster, while searching for pair with least distance
        c1 = 0; c2 = 0; i1 = 0; i2 = 0;
        sdis = 9999999999
        for i in xrange(nc):
            for j in xrange(i+1, nc):
                dis = euclidistance(nodes[i], nodes[j])
                if dis < sdis:
                    sdis = dis
                    c1 = nodes[i]; c2 = nodes[j];
                    i1 = i; i2 = j;
        # Merge these two nodes into one new node
        node = Node(c1.points + c2.points)
        node.left = c1; node.right = c2;
        
        #Remove the previous nodes, and add the new node
        new_nodes = []
        for i in xrange(nc):
            if i != i1 and i != i2:
                new_nodes = new_nodes + [nodes[i]]
        new_nodes = new_nodes + [node]
        nodes = new_nodes[:]
        nc = nc - 1

    return nodes

Kemudian terakhir, kita definisikan fungsi jarak yang kita pakai. Selain jarak euclidean, kita bisa yang digunakan kriteria jarak lainnya seperti Manhattan distance atau Chebyshev distance.

import math

def euclidistance(c1, c2):
    """ Calculate the distance between two cluster """
    dist = .0
    n1 = len(c1.points)
    n2 = len(c2.points)
    for i in xrange(n1):
        for j in xrange(n2):
            p1 = c1.points[i]
            p2 = c2.points[j]
            dim = len(p1)
            d = 0
            for k in xrange(dim):
                d = d + (p1[k]-p2[k])**2
            d = math.sqrt(d)
            dist = dist + d
    dist = dist / (n1*n2)
    return dist

Contoh
Untuk contoh pertama kita pakai dataset sintesis yang dihasilkan oleh dua buah distribusi normal multidimensi.

import upgma
import random
import matplotlib.pyplot as plt
import math

# Example 1
datapoints = [(random.normalvariate(2.5, 1.0), random.normalvariate(1.5,1.0)) for i in xrange(100)] + \
				[(random.normalvariate(-1, 0.5), random.normalvariate(3,0.5)) for i in xrange(100)]

# Plot datapoints before clustering
plt.plot([x for (x,y) in datapoints], [y for (x,y) in datapoints], 'k^')
plt.show()

# Cluster the data
nodes = upgma.upgma(datapoints, 2)
plt.plot([x[0] for x in nodes[0].points], [x[1] for x in nodes[0].points], 'b*')
plt.plot([x[0] for x in nodes[1].points], [x[1] for x in nodes[1].points], 'ro')
plt.show()

dan berikut keluaran hasil clustering jika kita pilih 2 sebagai jumlah cluster.
nocluster1cluster1

Contoh kedua kita ambil dataset old faithful geyser (http://www.stat.cmu.edu/~larry/all-of-statistics/=data/faithful.dat).

f = open('faithful.dat.txt', 'r')
lines = f.readlines()
f.close()

datapoints = []
for line in lines:
	tokens = line.split()
	datapoints += [(float(tokens[1]), float(tokens[2]))]

Karena fitur kedua berbeda skalanya dengan fitur pertama (puluhan berbanding dengan satuan), kita lakukan normalisasi z-score pada tiap masing-masing fitur dengan cara mengurangi dengan mean distribusi dan kemudian dibagi dengan standar deviasi.

avg1 = sum([x for (x,y) in datapoints])
avg2 = sum([y for (x,y) in datapoints])
centered_datapoints = map(lambda (x,y): (x-avg1, y-avg2), datapoints)
std1 = math.sqrt(sum(map(lambda x: x*x, [x for (x,y) in centered_datapoints])))
std2 = math.sqrt(sum(map(lambda x: x*x, [y for (x,y) in centered_datapoints])))
normalized_datapoints = map(lambda (x,y): (x/std1, y/std2), centered_datapoints)

Hasil clustering-nya adalah sebagai berikut.

# Before clustering
plt.plot([x for (x,y) in normalized_datapoints], [y for (x,y) in normalized_datapoints], 'k^')
plt.show()

# Cluster the data
nodes = upgma.upgma(normalized_datapoints, 2)
plt.plot([x[0] for x in nodes[0].points], [x[1] for x in nodes[0].points], 'b*')
plt.plot([x[0] for x in nodes[1].points], [x[1] for x in nodes[1].points], 'ro')
plt.show()

nocluster2cluster2

Kode lengkap dapat dilihat di: https://github.com/mitbal/py-upgma

Semoga berguna. Salam.

Pengalaman kuliah di swedia

Pada post kali ini, saya hendak membagi sedikit pengalaman saya dan hal-hal menarik yang saya temui setelah kurang lebih selama 7 bulan atau 28 purnama melanjutkan kuliah tingkat Master untuk program Machine Learning di KTH Royal Institute of Technology di Stockholm, Swedia.

Latar belakang

Semua itu bermula dan diawali dengan saya mendaftarkan diri kuliah di universitas di Swedia pada awal Januari 2013. Pendaftaran dilakukan di satu tempat terpadu, yaitu university admission (https://www.universityadmissions.se/intl/start) dengan membayar biaya pendaftaran sekitar 900 SEK. Untuk biaya kuliah dan biaya hidup, saya mendaftar ke beasiswa Swedish Institute (http://studyinsweden.se/scholarship/swedish-institute-study-scholarships/)

universityadmission

si scholarship

Setelah pengumuman penerimaan universitas lewat website, datanglah paket, kotak merah, dari KTH yang isinya kurang lebih kalendar, buku petunjuk mahasiswa baru, dan flash disk berisi video profil KTH.

kotakmerahkth.

Seminggu setelah pengumuman universitas, keluarlah pengumuman untuk beasiswa, dan Alhamdulillah nama saya keluar sebagai salah satu penerima dari Indonesia, bersama 14 teman saya lainnya.

Berangkatlah saya ke Swedia pada tanggal 15 Agustus 2013, di penghujung, akhir musim panas.

Tujuhbelasan

Karena saya berangkat sebelum tanggal 17 Agustus, maka saya merasakan tujuhbelasan di negeri orang. Melihat bendera merah putih berkibar di negeri orang adalah pengalaman yang cukup berkesan.

merahputih

Di kota Vienna ternyata ada bendera merah putih juga yang berkibar. Namun, ternyata itu adalah bendera kota Vienna itu sendiri.

benderavienna

Perkuliahan

kthdaridepan

Beban kuliah saya adalah 120 ECTS (European Credit Transfer and Accumulation System). Jika dibagi kedalam 2 tahun, maka saya harus menyelesaikan 60 credit untuk tahun pertama, 30 credit untuk semester 3, dan 30 credit sisanya untuk thesis.

Kuliah di dalam setahun dibagi menjadi 2 semester. Masing-masing semester dibagi lagi menjadi 2 period dimana masing-masing period kurang lebih berjalan selama 2 bulan. Dalam 1 period normalnya mengambil 2 mata kuliah yang masing-masing bebannya 7.5 credit walaupun hal ini bergantung dari mata kuliah dan program masing-masing.

Hal menarik lainnya adalah ujian akhir bisa berlangsung hingga 5 jam. Tak jarang mahasiswa membawa botol air minum dan makanan ringan agar bisa bertahan duduk mengerjakan soal selama itu. Selain itu ujian biasanya bisa diulang, dengan jarak sekitar 1 bulan setelah ujian sebelumnya berakhir, istilahnya reexam (walaupun saya belum pernah coba).

Yang menarik lagi, sistem perkuliahan di KTH menganut academic quarter, atau kuliah dimulai 15 menit dari waktu yang ditetapkan. Dan setiap satu jam sekali akan ada istirahat sekitar 15 menit. Hal ini sangat membantu apalagi kalau jadwal kuliahnya panjang langsung 4 jam. Bisa teler kalau tidak ada istirahat.

Perpustakaan

Setelah mendaftar ke kantor pajak Swedia (skatteverket) dan memiliki personnummer, maka kita bisa mendaftar dan meminjam buku dari perpustakaan Stockholm. Buku dapat dipinjam dari perpus manapun dan juga dapat dikembalikan ke perpus mana saja yang kita mau. Perpustakaan di Stockholm sendiri jumlahnya banyak, hampir tiap kommun memiliki perpus tersendiri. Namun yang terbesar tentunya adalah Perpus publik Stockholm atau Stockholm Stadsbiblioteket.

perpus

Kartu

Orang Swedia suka kartu. Total saya punya 13 kartu baru sejak datang ke Swedia.

kartu

Transportasi

Transportasi di Stockholm sangat bagus, dimana jumlah angkutan yang tersedia banyak dan memiliki jadwal yang tepat. Rute transportasi juga menjangkau hingga daerah-daerah terjarang di Stockholm. Namun kualitas yang bagus itu harus dibayar dengan harga tiket yang tidak murah. Satu kali naik sarana transportasi untuk zona yang sama harganya sekitar 36 SEK dan harga tiket bulanan untuk pelajar adalah 560 SEK atau hampir 1 juta rupiah.

kereta

Masjid

Ada masjid di Stockholm yang terletak di daerah Medborgarplatsen. Bisa dijangkau dengan menggunakan tunnelbana jalur hijau berhenti di Medborgarplatsen atau menggunakan bis nomor 59 arah Norra Hammarbyhamen. Khutbah jum’at biasanya menggunakan bahasa Arab, yang kemudian diterjemahkan ke bahasa Swedia.

masjid

Pos

Disini Swedia tidak ada lagi kantor pos. Sebagai gantinya, tersedialah banyak kotak surat di semua penghujung kota dimana masyarakat tinggal memasukkan surat kedalamnya yang kemudian akan diambil dan diantarkan oleh petugas setiap waktu tertentu. Perangko sendiri bisa dibeli di toko minimarket seperti Seven-Eleven dan pressbyran atau supermarket seperti ICA dan Co-op.

kotakpos

Stockholm

Kota Stockholm sendiri adalah kota yang sangat indah dan nyaman untuk dihuni. Berikut sedikit cuplikan kondisi Stockholm dari berbagai waktu dan tempat.

halloween

lampuwinter

3seasons

collage stockholm

Internet

Internetnya juga cukup kencang disini.

speedtest

Yak, demikian yang bisa saya utarakan pada post kali ini. Post berikutnya akan kembali membahas mengenai Machine Learning dan kerabatnya (kalau saya enggak malas). Untuk penutup, tinggal di luar negeri tidaklah mudah namun sangat layak untuk diperjuangkan. Hal yang diperoleh tidak hanya dalam bentuk ilmu yang didapat di kelas saja namun juga dari pengalaman bagaimana ketika kita berhadapan dan merasakan semua hal yang sebelumnya belum pernah ditemui. Hal ini bisa dalam bentuk pergaulan dengan orang-orang yang lebih beragam lagi latar belakangnya dibanding yang ditemui dari tempat asal namun juga kondisi geografis dan lingkungan yang bisa sangat berbeda dan membuat takjub walau padahal sebenarnya kita masih tinggal di planet yang sama.

Salam.

Transformasi Gambar Buta Warna

Pada post kali ini, kita akan menyimulasikan gambar yang kira-kira dilihat oleh mereka yang memiliki kekurangan penglihatan dalam hal membedakan warna atau buta warna dengan mengikuti metode yang diajukan oleh paper dengan judul Digital Video Colourmaps for Checking the Legibility of Display by Dichromats oleh Vienot et al. Hal ini tentunya akan berguna jika kita akan mendesain website atau papan pengumuman atau poster sehingga semua karya kita bisa dinikmati oleh semua orang.

Latar belakang

Pada retina di mata, manusia memiliki 2 jenis sel, yaitu sel batang (rod cell) dan sel kerucut (cone cell). Sel batang berguna untuk mengetahui tingkat kecerahan cahaya (brightness) dan berfungsi dengan baik ketika pencahayaan kurang seperti pada malam hari. Sedangkan sel kerucut bekerja ketika terdapat pencahayaan yang cukup dan berfungsi untuk membedakan warna. Terdapat tiga jenis sel kerucut yang masing-masing memiliki tingkat kesensitifan yang berbeda terhadap panjang gelombang warna, sel kerucut merah, hijau, dan biru. Persentase komposisinya kurang lebih 65% merah, 33% hijau, dan 2% biru.

Makhluk hidup yang memiliki 3 jenis sel kerucut dengan sensitivitas berbeda disebut trichromats. Beberapa hewan karnivora seperti anjing hanya memiliki dua jenis sel kerucut, alias dichromats. Sedangkan burung dan beberapa jenis ikan memiliki 4 jenis sel kerucut yang berbeda sehingga bisa disebut tetrachromats.

Buta warna sendiri adalah kondisi ketika manusia kekurangan satu jenis sel kerucut. Buta warna diperkirakan menimpa 8% dari populasi laki-laki di seluruh dunia. Ada dua jenis buta warna yang akan disimulasikan pada post ini, protan dan deutan. Protan terjadi karena mata hanya memiliki sel kerucut hijau dan biru sedangkan Deutan terjadi ketika mata hanya memiliki sel kerucut merah dan biru.

Implementasi

Berikut kode dalam Matlab.

function [ pim, dim ] = MakeDichromatIms( im )
%This function transform the input image into two different images how they
%perceived by dichromats people (protan and deutan)

    im = double(im);

    % Normalize transform the original RGB value
    im1 = (im/255).^(2.2);
    R = im1(:, :, 1);
    G = im1(:, :, 2);
    B = im1(:, :, 3);

    % Protan transform
    pR = 0.992052*R + 0.003974;
    pG = 0.992052*G + 0.003974;
    pB = 0.992052*B + 0.003974;

    % Deutan transform
    dR = 0.957237*R + 0.0213814;
    dG = 0.957237*G + 0.0213814;
    dB = 0.957237*B + 0.0213814;

    % Transformation matrix from RGB to LMS
    M = [17.8824 43.5161 4.11935;
         3.45565 27.1554 3.86714;
         0.0299566 0.184309 1.46709];

    % Protan projection
    P = [0 2.02344 -2.52581; 0 1 0; 0 0 1];

    % Deutan projection
    D = [1 0 0; 0.494207 0 1.24827; 0 0 1];

    % Precompute the transformation matrix before loop to speed things up
    Tp = inv(M)*P*M;
    Td = inv(M)*D*M;

    % Allocate the output image
    pim = zeros(size(im));
    dim = zeros(size(im));

    % Apply the transformation for each pixel
    for ii=1:size(im, 1)
       for jj=1:size(im, 2)
           protan = Tp*([pR(ii,jj) pG(ii,jj) pB(ii,jj)]');
           deutan = Td*([dR(ii,jj) dG(ii,jj) dB(ii,jj)]');

           pim(ii, jj, 1) = protan(1); pim(ii, jj, 2) = protan(2); pim(ii, jj, 3) = protan(3);
           dim(ii, jj, 1) = deutan(1); dim(ii, jj, 2) = deutan(2); dim(ii, jj, 3) = deutan(3);
       end
    end

    % Reverse the initial transform
    pim = 255*(pim.^(1/2.2));
    dim = 255*(dim.^(1/2.2));
end

–Edit–
Berikut implementasi yang memanfaatkan perkalian matrix di Matlab sehingga waktu eksekusinya 10x lebih cepat dibanding kode di atas.

function [ pim, dim ] = MakeDichromatIms2( im )
%This function transform the input image into two different images how they
%perceived by dichromats people (protan and deutan) faster using matrix
%operation in Matlab

    im = double(im);
    
    % Normalize transform the original RGB value
    im1 = (im/255).^(2.2);
    R = im1(:, :, 1);
    G = im1(:, :, 2);
    B = im1(:, :, 3);
    
    % Protan transform
    pR = 0.992052*R + 0.003974;
    pG = 0.992052*G + 0.003974;
    pB = 0.992052*B + 0.003974;
    
    % Deutan transform
    dR = 0.957237*R + 0.0213814;
    dG = 0.957237*G + 0.0213814;
    dB = 0.957237*B + 0.0213814;
    
    % Transformation matrix from RGB to LMS
    M = [17.8824 43.5161 4.11935; 
         3.45565 27.1554 3.86714; 
         0.0299566 0.184309 1.46709];
    
    % Protan projection
    P = [0 2.02344 -2.52581; 0 1 0; 0 0 1];
    
    % Deutan projection
    D = [1 0 0; 0.494207 0 1.24827; 0 0 1];

    % Precompute the transformation matrix before loop to speed things up
    Tp = inv(M)*P*M;
    Td = inv(M)*D*M;
    
    % Apply the transformation using matrix operation
    PP = Tp * [pR(:)'; pG(:)'; pB(:)'];
    DD = Td * [dR(:)'; dG(:)'; dB(:)'];
    
    % Reverse the initial transform
    PP = 255*(PP.^(1/2.2));
    DD = 255*(DD.^(1/2.2));
    
    % Reshape the computed vector back
    pim = zeros(size(im));
    pim(:,:, 1) = reshape(PP(1, :), size(R));
    pim(:,:, 2) = reshape(PP(2, :), size(G));
    pim(:,:, 3) = reshape(PP(3, :), size(B));
    
    dim = zeros(size(im));
    dim(:,:, 1) = reshape(DD(1, :), size(R));
    dim(:,:, 2) = reshape(DD(2, :), size(G));
    dim(:,:, 3) = reshape(DD(3, :), size(B));
end

Contoh keluaran dari program.

firetruck

flowers

Semoga berguna. Salam

Essay discovery of computer

Pada post kali ini, saya akan membagi tulisan saya dalam essay 4 halaman yang berjudul discovery of computer. Tulisan ini membahas sedikit mengenai perjalanan bagaimana komputer dahulu pertama dikonsepsikan hingga bisa direalisasikan menjadi sekarang. Tentunya tulisan ini bukan sejarah komprehensif melainkan ingin memberikan sedikit sudut pandang dengan kaitannya terhadap bagaimana science berperan dalam perkembangannya.

Salam,

essay_thumb