GNU datamash Nedir? Nasıl Kullanılır?

Güncelleme Yayın

Tablo özeti oluşturma işlemlerine devam ederken, komut satırı aracılığıyla pratik bir şekilde kullanabileceğimiz, GNU projesi kapsamında geliştirilen ve cross-tabulation (crosstab) ile pivot table oluşturmamızı da mümkün kılan ek bir araçtan daha bahsetmek istiyorum; datamash. Daha öncesinde awk ve sed komutlarının kullanımına temel düzeyde değinmiştim. datamash, awk ve sed esasında temel düzeyde işlemler için hemen hemen her zaman elimizin altında kolaylıkla ulaşabileceğimiz araçlar ve bu nedenle el alışkanlığı sağlamanın faydalı olacağını düşünüyorum.

GNU datamash

GNU datamash az önce de belirttiğim üzere komut satırı aracılığıyla aktardığımız dosya üzerinden basit hesaplama (count, sum, min, max, mean, stdev, string coalescing gibi) işlemleri gerçekleştirebileceğimiz bir program. Oldukça zengin istatistiksel fonksiyonlar (mean, 1. çeyrek, median, 3. çeyrek, IQR, standart sapma, Jarque-Bera sınaması) barındıran datamash ile ilgili daha detaylı bilgiye GNU Operating System > GNU datamash sayfasından ulaşmak mümkün1. İndirme işlemi için brew kullanabilirsiniz.

brew install datamash

datamash Kullanımı

Temel bilgi verdikten sonra örneklerle programın kullanımını inceleyebiliriz. Unutmadan, datamash aksi belirtilmediği sürece field delimiter olarak tab space (TSV; Tab-separated values) işleme almakta ve yine aksi belirtilmedikçe başlık (header) alanlarını yok saymakta. datamash en yalın haliyle şu şekilde kullanılabilir.

seq 10 | datamash sum 1 mean 1

İlgili başlık altında da belirttiğim üzere datamash bir girdiye ihtiyaç duymakta. Açıklama alanında bunun bir dosya olabileceğini belirtmiştim. Ancak, pipe ile de verileri aktararak sayısal işlemler gerçekleştirebiliriz. Yukarıdaki örnekte seq ile 1’den 10’a kadar sayıları listelemekte ve bu sayıları pipe (|) ile datamash’e aktarmaktayız. datamash sum ise bu değerler arasındaki 1. sütunun (toplamda 1 sütun olsa da; line 1 has only 1 fields) değerlerinin toplamını ve yine 1. sütundaki verilerin ortalamasını ekrana döndürecektir. Hemen bir sorgulama yapalım ve bu ifademizin geçerliliğini kontrol edelim.

seq 10 | datamash check

Yukarıdaki komut yine bir önceki örnekte olduğu gibi seq ile 1’den 10’a kadar sayıları listelemekte. Önceki örnekten farkı pipe sonrasındaki adımda. seq ile edindiğimiz verileri aktardığımızda datamash bu defa verilerin geçerliliğini kontrol etmekte ve özet bir şekilde sonucu döndürmekte. Bu durumda, komutu uygulamamızın ardından alacağımız dönüş şu şekilde olacaktır.

10 lines, 1 field

Şimdi işleri biraz daha detaylandıralım ve işlemler için veri dosyaları (txt, csv vb.) kullanalım.

OrderDate Region Rep Item Units UnitCost Total
1.6.18 East Jones Pencil  95 1,99 189,05
1.23.18 Central Kivell Binder 50 19,99 999,50
2.9.18 Central Jardine Pencil 36 4,99 179,64
2.26.18 Central Gill Pen 27 19,99 539,73
3.15.18 West Sorvino Pencil 56 2,99 167,44
4.1.18 East Jones Binder 60 4,99 299,40
4.18.18 Central Andrews  encil 75 1,99 149,25
5.5.18 Central Jardine Pencil 90 4,99 449,10

Yukarıdaki gibi bir içeriğimiz olduğunu varsayalım. Dikkat edeceğimiz hususlar şunlar; sütunların tab ile ayrılmış ve ilk satırda sütun isimleri yer almakta. Dosyanın adının order.txt olduğunu varsayalım. İlk işlem olarak verilerimizi kontrol edelim.

datamash check < order.txt

Alacağımız dönüş şu şekilde olacaktır.

9 lines, 7 fields

Elbette dosya içeriğini yönlendirici yerine < (I/O Redirection) cat komutunu da kullanabiliriz.

cat order.txt | datamash check

Şimdi seq ile gerçekleştirdiğimiz örneği order.txt dosyasındaki 5. sütun (Region) için gerçekleştirelim. Komutumuzu ilk olarak herhangi bir header bildirimi olmaksızın işleme alalım.

datamash sum 5 mean 5 < order.txt

Komutu uyguladıktan sonra büyük ihtimalle şu dönüşü alacağız. Bunun nedeni OrderDate'nin bir başlık değil sayısal değer olarak ele alınmak istenmesi ancak veri tipinin buna müsade etmemesi olarak açıklanabilir.

datamash: invalid numeric value in line 1 field 1: 'OrderDate'

O halde ya başlıkları sileceğiz ya da ilk satırın başlıklardan oluştuğunu belirtmeliyiz. Bunun için --header-in ve --header-out parametrelerini kullanabiliriz. --header-in ilk satırın başlıklardan oluştuğunu belirtmektedir.

datamash sum 5 mean 5 --header-in < order.txt

Komutu uygulamamızın ardından şu dönüşü alırız.

489 61.125

Peki, dönüşün yine başlıklarla ifade edilmesini istersek? O zaman -H parametresini de komutumuza ekleyebiliriz.

datamash -H sum 5 mean 5 --header-in < order.txt

Bu durumda dönüş şu şekilde değişiklik gösterecektir.

sum(Units) mean(Units)
489 61.125

-H ile sum ve mean işlemlerinin başlıkla döndürülmesini isteyebiliriz. Bu durumda datamash ilk satırın başlıklar taşıdığını varsayacaktır ve şu şekilde dönecektir.

sum(Units) mean(Units)
489 61.125

Ek bir not daha, check işlemini --header-in ile gerçekleştirdiğimizde de yukarıdakiyle aynı sonucu alırız. Aynı şekilde --header-in belirtmeden -H parametresini de kullandığımızda sum ve mean değerleri değişmeyecektir. Fakat, başlıkları silerek --header-in parametresini kullandığınızda ilk alan yine başlık olarak değerlendirileceği için değerler farklılık gösterir. Örnek işlemlerimizi biraz daha detaylandıralım.

datamash -H --header-in sum 5,7 mean 5 min 5 max 5 < order.txt

Komutu uygulamanızın ardından datamash: invalid numeric value in line 2 field 7: '189,05' şeklinde bir hata alırsınız. 5. sütunda (Units) yer alan değerlerde decimal separator olarak comma (,) kullanıldığı için sayısal işlem gerçekleştirilemeyecektir. Bu aşamada dosya içeriğinde değişiklik yapabilir ya da alternatif çözümler üretebiliriz. Ben sed komutunu kullanarak tek satırda virgüllerin nokta olarak değiştirilmesini ve ardından elde edilen verilerin pipe ile datamash'a aktarılmasını sağlamanın daha pratik olacağında karar kıldım.

sed '/[0-9]\./s/\,/./g' order.txt | datamash -H --header-in sum 5,7 mean 5 min 5 max 5

Komutun uygulanmasının ardından alacağımız dönüş şöyle olacaktır.

sum(Units) sum(Total) mean(Units) min(Units) max(Units)
489 2973.11 61.125 27 95

Komutta sum 5,7 ifadesini görmektesiniz. Virgül ile belirtmek koşulu ile istediğimiz bir sayısal işlemi aynı anda farklı sütunlar için de gerçekleştirebilmekteyiz. Yazının başında da belirttiğim üzere datamash sütun ayrımını (field delimiter) ön tanımlı olarak değerlendirmekte. Peki, farklı durumlarda (örneğin virgül (,), boşluk ( ), noktalı virgül (;), pipe (|)...) gibi kullanımlarda ne yapabiliriz?

OrderDate;Region;Rep;Item;Units;UnitCost;Total
1.6.18;East;Jones;Pencil;95;1,99;189,05
1.23.18;Central;Kivell;Binder;50;19,99;999,50
2.9.18;Central;Jardine;Pencil;36;4,99;179,64
2.26.18;Central;Gill;Pen;27;19,99;539,73
3.15.18;West;Sorvino;Pencil;56;2,99;167,44
4.1.18;East;Jones;Binder;60;4,99;299,40
4.18.18;Central;Andrews;Pencil;75;1,99;149,25
5.5.18;Central;Jardine;Pencil;90;4,99;449,10

Verilerimizin yukarıdaki gibi ; ile ayrılmış olduğunu (csv; comma separated) varsayalım. Bu durumda -st parametresini kullanarak ilgili ayırıcıyı (delimiter) belirtmemiz gerekir.

sed '/[0-9]\./s/\,/./g' order.txt | datamash -st ';' -H --header-in sum 5,7 mean 5 min 5 max 5

-st ';' delimiter tanımıyla birlikte kodumuzu uyguladığımızda şu sonucu alırız.

sum(Units);sum(Total);mean(Units);min(Units);max(Units)
489;2973.11;61.125;27;95

Bir hatırlatma daha, --sort --headers yerine -sH de kullanabiliriz ve alacağımız dönüş aynı olur.

sed '/[0-9]\./s/\,/./g' order.txt | datamash -st ';' -sH --header-in groupby 2 mean 5 sstdev 5
Central;55.6;26.425366601052
East;77.5;24.748737341529
West;56;nan

### datamash cross-tabulation (crosstab)

Son olarak, yazının giriş bölümünde de bahsi geçtiği üzere datamash ile temel sayısal işlemler de gerçekleştirebileceğimiz tablo özetleme (pivot) işlemine bir bakalım ve yukarıdaki örneğimiz üzerinden sadece ilgil sütunları değiştirerek devam edelim.

sed '/[0-9]\./s/\,/./g' order.txt | datamash -st ';' -H --header-in crosstab 2,4 sum 7

Komutumuzu uygulamamızın ardından şu karşılığı alırız.

GroupBy(Region);GroupBy(Item);sum(Total)
;Binder;Pen;Pencil
Central;999.5;539.73;777.99
East;299.4;N/A;189.05
West;N/A;N/A;167.44

İlk satırda gruplanmış olarak Region (2) ve Item (4) yer almakta; crosstab 2,4. 2, 3 ve 4. satırlarda Region temelinde gruplanmış alanların (Region ve Item) toplamlarını görmekteyiz. N/A ilgili verilerin olmadığını ve dolayısıyla sum işleminin gerçekleştirilemediğini göstermektedir.

Özet Olarak

datamash ile ilgili özet işlemlerin ardından sonraki yazılarda daha kapsamlı işlemlerle devam edeceğiz. Bu amaçla sed ve awk'nin de ortak bir şekilde kullanılacağı pek çok çözümlememiz söz konusu olacak. Öncesinde datamash ile ilgili daha detaylı bilgi almak isterseniz şu kaynakları öneririm.