18 Ocak 2015 Pazar

Cezbedici Biyoinformatik 1 - Veri İşleme ve Linux'un Güzelliği


Çoğu bilgisayar programlamacısının programlamayı deli gibi sevdiklerini biliriz. Eğer severek planladıkları bir proje üzerinde çalışıyorlarsa bilgisayar başında saatlerini geçirirken ne acıkınca acıktıklarının farkına varırlar, ne de yanlarında olup bitenin. Çok iyi bir programlamacı sayılmasam da farkına varmadan 10 saat aralıksız kod başında zaman geçirmişliğim çok olmuştur ve bu ben de programlamayı bu denli sevenler arasına katabilirim kendimi. Peki ya programlayı veya Biyoinformatik'i bu kadar cezbedici kılan ne?


Bu sorunun tek bir cevabı yok elbette. Ama bence en büyük zevklerden biri “akıllıca ve kısaca bir kod ile çokça işler yapabiliyor olma yetisi”nde gizli. :) 100 milyar baz dizisinin her bir satırında istediğiniz değişikliği yalnızca 5-10 harflik bir kod ile bilgisayara anlatabiliyor, ve bu değişikliği 1 saniyede gerçekleştirebiliyor oluşunuz... Söylemesi bile zevk verici. Hele enter tuşuna bastıktan sonra o değişikliği izlemesi… :)


İşte bu denli akıllıca veri işleyebileceğiniz araçlardan bir tanesi ile Linux.  Linux ile tanıştığımda üniversite ikinci sınıfta bir araştırma laboratuarında çalışıyordum. İlk bilimsel araştırma tecrübelerimden biriydi. Ama laboratuarda bana Linux’u öğreten arkadaşım öğretmeye başlamadan önce bu sistemin isminin Linux olduğunu söylememişti. :) Ve ben ismini bilmeden o labda Linux’a ufak bir giriş yapmış oldum. Sonrasında sömestr tatilinde AG Biyoinformatik’te yaptığım stajda sevgili meslektaşım Ahmet Raşit Öztürk, bana Linux’tan bahsetmeye başlayınca öğrendiğim program hakkında bir aydınlanma yaşamıştım. :) “Çok bilen anlamatamaz” diye bir deyim vardır, her ne kadar bunun genellenmesini doğru bulmuyor olsam da bir çok kişi için bu deyimin doğru olduğuna inanıyorum. Programın ismini söylemeden bana anlatmaya başlayan arkadaşım gibi. :)

Peki nedir bu Linux’un güzelliği? Saymakla bitmez. Ama bunlardan aklıma gelen bir kaç örneği paylaşacağım sizlerle. İlk örneğim şöyle :

Lisansımın son senesinde bir grup arkadaşımla Psikoloji bölümünde ufak bir araştırma yapmıştım. Boğaziçi Üniversitesi’nde Görsel Sinir Bilimi (Visual Neuroscience) çalışan İnci Ayhan isminde bir hocamızın süpervizörlüğü altında görsel adaptasyonun zaman algısı üzerindeki etkisini ölçüyorduk. Görsel adaptasyonu insanlar üzerinde test etmek için bilgisayarda belli frekanslarda yanıp sönen objeler oluşturan bir Matlab kodunu kullanıyorduk. Deneyi yapıp datalarımızı topladıktan sonra Matlab kodundaki ufak bir hata, Matlab’ın bize vermiş olduğu sonuç raporlarında bir değişikliğe sebep olmuştu. Matlab’ın sonuç olarak verdiği dosyaların her birinde anlamsız harf dizilerinden oluşan bir çok değişik satır yer alıyordu. Bütün dosyalardan satırların her birini teker teker kaldırmak oldukça uzun ve yorucu bir iş olurdu. Bu satırları kaldırmadan ise projemizin bir sonraki adımına geçemiyorduk çünkü bir sonraki adımda kullanacağımız program bu bozuk dosyalarımızı okuyamıyordu. İşte tam bu gibi anlar Linux’un devreye girip cezbedici güzelliğiyle hayat kurtardığı anlardır. :) Linux sayesinde ufak bir kod ile istediğimiz değişiklikleri tek bir satırda yapmıştık. O cankurtaran kod şu idi:


        for files in *.dat; do sed '/^2.*/d' $files>new; mv new $files; done



Linux'un Maskotu Tux

Peki bu kod ne anlama geliyor? Bunu da açalım ve Linux ile Veri işleme kavramı kafamızda güzelce şekillensin.

Datamızdaki istemediğimiz absürt satırların her biri  2.415000e+02 dizisi ile başlıyordu. Datamızdaki istediğimiz satırlarımızın hiç birisi ise 2 rakamı ile başlamıyordu. Bunu farkettikten sonra problemi çözmek için şöyle bir çözüm yolu düşündüm: "Eğer bilgisayara 2 ile başlayan bütün satırları silmesini söylersem istemediğim datayı temizlemiş olurum, kendi datamızda 2 ile başlayan başka  bir satır olmadığı için yanlış bir şeyi de silmemiş olurum."


Yukarıda paylaştığım kodun sed '/^2.*/d’ parçası 2 ile başlayan satırları silme işlemini yapıyor. Şimdi bu sed '/^2.*/d’ komutunu anlamaya çalışalım.

Sed komutunun bir kaç çeşit çalışma mantığından bir tanesi şu şekildedir:

sed ’s/benimdizim/d’ benimdosyam

Bu komut benimdosyam isimli dosyanız içindeki benimdizim isimli diziyi siliyor. En başta yazmış olduğum koda kısaca bakarsanız benimdizim yazan yerde ^2.* yazmış olduğunu göreceksiniz. Peki ^2.* ile ne demek istiyoruz?

Bilgisayarcılıkta düzenli ifadelerde (regular expressions) bazı karakterlerin düzenleyici görevleri vardır. Örneğin:

^ (şapka işareti) satır başını bulmayı temsil eder.

. (nokta) her hangi bir karakteri temsil eder.

* (yıldız) kendisinden bir önceki gelen karakterin her hangi bir miktarda tekrarlanabileceğini ifade eder.

Şimdi bu bilgiler ışığında ^2.* ifadesine tekrar bakalım; ve bunun satır başında 2 ile başlayan ve sonrasında herhangi bir karakterin her hangi bir miktarda tekrarlanabileceği diziyi bul” manasına gelmiş olduğunu anlamaya çalışalım.

Bu yazıyı hala okumaya devam ediyorsanız sizi tebrik ediyor, ve Linux dünyasına hoş geldiniz diyorum. :) Sıkıldıysanız da Linux’un size göre olmadığı düşüncesine kapılmayın, bunun sebebinin burada konuya oldukça hızlı bir giriş yapmamla alakalı olması da   muhtemel.

Peki vermiş olduğum kodun başındaki for files in *.dat; do ifadesi ne anlama geliyor?

Bu da aslında bir for döngüsünü (for loop) ifade ediyor. Ben 2 ile başlayan satırları yalnızca belirli dosyadan değil, klasördeki .dat uzantılı bütün dosyalarından tek hamlede silmek istiyordum. Bunun için Linux’a .dat uzantılı bütün dosyaları bulmasını, ve sed komutu ile belirttiğim silme işlemlerini bu dosyalardan yapmasını söyledim. Bu gibi döngü şeklinde yapılması gereken işlerde for döngüsünü kullanabiliriz. For döngüsünü Linux’da kısaca şu şekilde çalışır:

for  arg in [list];
  do
      command
  done

Başta verdiğim kodumuzun kısa bir halini farklı satırlara bölerek tekrar yazıp  benzerliği görmeye çalışalım:

for files in *.dat;
   do
      sed '/^2.*/d'
   done

Kısacası: ".dat uzantılı bütün dosyalara git ve  sed '/^2.*/d’ komutunu gerçekleştir" demiş olduk.

Son olarak, yeni oluşturduğum değişikliklerin dosyaya kalıcı olarak kaydedilmesini istiyordum. Bunun için ise kodun sonuna  $files>new; mv new $files ifadesini ekledim. Aslında bu ifadeyi hiç yazmasam da komutum çalışıyordu, fakat değişiklikler dosyaya  kaydedilmiyor, yalnızca sonuç ekranda görüntüleniyordu. Bunun için değişiklikleri önce yeni bir yere (new) kaydettim, sonrada bunları dosyaya geri taşıdım (mv: move). Ve bunu $files>new; mv new $files komutu ile yaptım.

Daha sonradan sed komutu üzerinde bir araştırma yaparken değişiklikleri dosyaya kaydetmeye yarayan bir -i seçeneği olduğunu farkettim. Öyle görünüyor ki aslında $files>new; mv new $files kullanmak yerine sed -i seçeneğini kullanarak daha kısa şekilde de bu kodu yazabilirmişim. 

Örneğimizi özetleyecek olursak, bir satırlık kod ile istediğimiz tüm dosyalardaki belli satırları silmiş olduk. Google gibi artistlik yapacak olursak: 0.023 saniyede 325000 satırda değişiklik yaptık. :) (Bu sayılar gerçek değildir. )

Bir sonraki yazımda başka bir Linux’un güzelliği örneği ile bu konuya devam ediyor olmayı planlıyorum. Fakat ne kadar kişinin Linux ile ilgilendiğini ve farklı kullanım örneklerini duymak istediğini bilmediğim için bundan çok emin değilim. Bunun için yazı hakkındaki yorumlarınızı, sorularınızı, bu tür / bundan daha basit / bundan daha ağır bir örnek daha okumak isteyip istemediğinizi bana email olarak gönderirseniz sevinirim.

Bana bu blogda yer veren meslektaşım Ahmet Raşit Bey’e çokça teşekkür ediyorum. Düzenli İfadeleri (Regular Expressions) ilk olarak onun şirketindeki stajım sırasında öğrendim. Umarım bu bloğun yazarları olarak sayımız gün geçitikçe  çoğalır ve birbirimize katkılarımız artar. Bu blogdaki Sözün özü ve Meraklısına isimli bitiriş başlıkları çok hoşuma gitmişti. Deniz ve Osman arkadaşımın bu geleneği devam ettirdiği gibi ben de devam ettirmek istiyorum. Biyoinformatik meraklılarını problemsiz kalmasın! :)

Sözün Özü: Linux güzeldir, zekidir, işinizi inanılmaz kolaylaştırır, ve size bir kaç harf dizisi ile harikalar yaratır.

Meraklısına: sed komutunun farklı kullanımlarını internetten araştıralım bulalım. Bu komutu kullanarak “Biyoinformatik tr” dizisindeki ortanca i harfini e harfine çevirerek bu diziyi “Biyoenformatik tr” haline getiren bir kod yazmaya çalışalım. Cevaplarınızı doğrulamak için bana email gönderebilirsiniz.