GNU datamash Nedir? Nasıl Kullanılır?
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.