Komut Satırı & Bash

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

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 ...
GÖRSEL
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ün. İ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	Pencil	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.

HABERDAR OL

Yeni eklenen projeler, eğitimler, içerikler ve yayınlanan videolar e-posta adresine gelsin.