Groupby

pandas
veri önişleme
Author

Birol Yüceoğlu

Published

October 30, 2017

Pandas paketi veri analizi ve işlemesi için hazırlanmış bir Python paketidir. Bu paket çeşitli formatlardaki dosyaları (Excel, Csv, Txt gibi) okumayı, bu formatlarda dosyalar oluşturmayı kolaylaştırır. Aynı zamanda pandas paketi ile oluşturulan veri çerçeveleri (dataframe) sayesinde farklı formatlardaki (sayı, metin, tarih) veriyi birlikte tutmak, bu verileri işlemek ve basit analizler yapmak mümkündür.

Pandas paketinin altındaki bir yöntem olan groupby() ham haldeki veriden (örnek olarak alışveriş verisi) çeşitli istatistikler çıkarmak için oldukça yararlı bir araç. Bu Veri Defteri’nde UCI Machine Learning Repository’de bulunan online satış verisini kullanacağız. Veriye linke tıklayarak erişebilirsiniz. İlk olarak veriyi okutarak ve boyutlarına bakarak başlayalım.

# İlk adımda pandas ve numpy paketlerini yüklüyoruz
import pandas as pd
import numpy as np
from IPython.display import display, HTML
# Input dosyasının olduğu klasörün yolu
IDIR = 'D:/Data/Blog/Data/'

# Pandas'ın altındaki read_excel fonksiyonuyla Excel dosyasını okutabiliriz.
# Pandas aynı zamanda csv, table, sql ve kopyaladığınız tablo halindeki verileri de okuyabilir (clipboard).
# read_csv, read_table, read_json, read_sql, read_clipboard fonksiyonlarını inceleyebilirsiniz.
# Şimdi veriyi okutarak verinin boyutlarını inceleyelim.
df = pd.read_excel(IDIR + 'Online Retail.xlsx')

print("Veri çerçevesinin boyutu: " + str(np.shape(df)))

Veride 8 kolon var. Kolonlar hakkındaki ilk bilgiyi head() fonksiyonuyla görebiliriz.

HTML(df.head().to_html())

Verideki kolonların ne anlama geldiğine bakalım.

Kolon Anlam
InvoiceNo Fatura numarası, her alışverişin bir numarası var
StockCode Ürünün numarası
Description Ürünün açıklaması
Quantity Üründen kaç adet alındığı
InvoiceDate Alışverişin tarihi ve saati
UnitPrice Ürünün birim fiyatı
CustomerID Müşteri numarası
Country Ülke

Öncelikle ülke bazında alışveriş istatistikleri çıkaralım. Bu amaçla ilk yapacağımız şey veri setini ülke bazında gruplamak.

# Veriyi ülke (Country) bazında grupluyoruz
df_country = df.groupby('Country')

Veride hangi ülkeler olduğunu görmek için group.keys(), kaç ülke olduğunu görmek içinse ngroups metotlarını kullanabiliriz.

print("Ülkeler")
print(df_country.groups.keys())
print("Ülke sayısı: " + str(df_country.ngroups))

Veri setinde 38 ülkeden yapılan alışverişler var. Her bir gruba (ülkede yapılan alışverişlere) erişmek için aşağıdaki gibi bir loop kullanabiliriz. df_country bir GroupBy objesi ve veriyi ülke ve satış verisini içeren bir dictionarye benzer bir şekilde tutuyor.

for country, sales in df_country:
    if country == 'Belgium':
        HTML(sales.head().to_html())

İstediğimiz gruba ulaşmanın bir diğer yolu da get_group() fonksiyonu. ‘Austria’ için olan satış verilerine ulaşmayı deneyelim.

HTML(df_country.get_group('Austria').head().to_html())

Şimdi her ülke için en çok satılan ürünü bulalım. Bunun için yapmamız gerekenler ülke (Country) ve ürün (StockCode) bazında satış miktarlarını (Quantity) toplamak olacak. Ondan sonra da her ülke için en çok satılan ürünü bulacağız. groupby fonksiyonuna vereceğimiz by argümanı hangi kolonlara göre (Country, StockCode) gruplayacağımız bilgisini veriyor. Daha sonra işlem yapacağımız kolonu (Quantity) ve yapacağımız işlemi (sum()) belirtiyoruz.

df_country_product = df.groupby(by = ['Country', 'StockCode'])['Quantity'].sum()
print(df_country_product.head())

Dataframe yapısını korumak için reset_index() fonksiyonunu kullanabiliriz.

df_country_product = df_country_product.reset_index()
HTML(df_country_product.head().to_html())

Ülke bazında en yüksek miktara sahip ürünleri bulmak için groupbyı maksimum değeri bulacak şekilde kullanabiliriz. Ancak bu ürün bilgisini vermeyeceği için transform yöntemini kullanıyoruz. Bu sayede her ülke için maksimum satış değerine sahip ürünün satış adedine erişiyoruz. Aşağıdaki satırda değeri maksimum satışa sahip ürünlere sahip indexleri belirliyoruz. Bu, aynı satış miktarına sahip birden fazla ürün varsa onları da bulmamızı sağlar.

idx = df_country_product.groupby(['Country'])['Quantity'].transform(max) == df_country_product['Quantity']

HTML(df_country_product[idx].head(10).to_html())

Şimdi de müşteriler için çeşitli istatistikler çıkaralım. Müşterilerle ilgili pazarlama, segmentasyon, müşteri terki tahmini gib çalışmalarda sıklıkla kullanılan RFM (Recency, frequency, monetary / yakınlık, sıklık, mali) değişkenlerini groupby fonksiyonunu kullanarak oluşturacağız. Bu tip istatistikler aynı zamanda gerçekleştireceğiniz çalışmalarda öznitelik türetmek için de kullanılabilir.

Her müşteri için aşağıdaki değişkenlerin değerlerini elde etmek istiyoruz: * Alışveriş sayısı * Toplam ve ortalama alışveriş miktarı * Satın alınan toplam ve ortalama (farklı) ürün sayısı * En son alışveriş tarihi

Bunun için öncelike toplam alışveriş miktarını ‘Amount’ kolonuna yazdıracağız. Yapmamız gereken miktar (Quantity) ile birim fiyat (UnitPrice) kolonlarını çarpmak.

Bunları yapmadan önce müşteri (CustomerID) kolonunda boş değerler olduğu için öncelikle bu alışverişleri veri setinden çıkaralım.

# CustomerID değeri olmayan müşterileri veri setinden çıkaralım.
print("Temizlik öncesi alışveriş sayısı: " + str(len(df)))
df = df[df['CustomerID'] > 0]
print("Temizlik sonrası alışveriş sayısı: " + str(len(df)))

# Birim fiyat ve miktar değerlerini çarparak toplam tutarı bulalım.
df['Amount'] = df['Quantity'] * df['UnitPrice']
HTML(df.head().to_html())

Alışverişleri önce müşteri (CustomerID) ve alışveriş (InvoiceNo) değerleri için gruplayalım. Bu sayede her alışveriş için sepetteki ürün sayısı ve sepetteki ürünleri toplam tutarını öğrenebiliriz. Her alışveriş için yapacağımız işlemler aşağıdakilerdir: * Farklı ürün sayısını bulmak (StockCode): Kullanacağımız yöntem nunique kaç tane tekil (unique) değer olduğuna bakar. * Sepetteki ürünlerin değerini toplamak (Amount): Kullanacağımız yöntem sum verilen kolonun değerlerini toplar. * Alışveriş tarihini belirlemek (InvoiceDate): Kullanacağımız değer max maksimum değeri verir. Burada max değerini kullanmamız şart değil. Sadece bu değeri bir sonraki tabloya da aktarmak istiyoruz.

agg fonksiyonu dictionary yapısıyla bu farklı işlemleri tek satırda yapmamıza imkan tanıyor.

df_customer = df.groupby(['CustomerID', 'InvoiceNo']).agg({'StockCode':'nunique', 
                                                           'Amount':'sum', 
                                                           'InvoiceDate': 'max'}).reset_index()

HTML(df_customer.head().to_html())

Artık istediğimiz değerleri hesaplayabiliriz. Her müşteri ve alışveriş için oluşturduğumuz tabloyu müşteri bazında tekrar gruplayacağız. Yapmak istediğimiz işlemler aşağıdakilerdir: * İşlem sayısını bulmak: ‘InvoiceNo’ kolonundaki değerleri sayacağız. Değerler tekil olduğu için count fonksiyonunu kullanabiliriz. * Toplam ve ortalam işlem miktarını bulmak: ‘Amount’ kolonu için toplam ve ortalama (mean) değerleri bulacağız. * En son alışveriş tarihini bulmak: Her müşteri için ‘InvoiceDate’ kolonundaki maksimum değeri bulacağız.

Miktar kolonunda yapacağımız iki işlem (toplam ve ortalama) için de dictionary yapısını ya da bir liste kullanabiliriz.

df_customer = df_customer.groupby('CustomerID').agg({'InvoiceNo':'count', 
                                                     'Amount': ['sum','mean'],
                                                    'InvoiceDate': 'max'}).reset_index()

df_customer.columns = ['CustomerID', 'Number_of_Transactions', 'Total_Amount', 'Average_Amount', 'Last_Transaction_Date']
HTML(df_customer.head().to_html())

groupby()fonksiyonunu kullanarak veriyi özetledik. Bu noktadan sonra uygulamanıza göre veriden özetlediğiniz bilgileri kullanabilirsiniz.

Jupyter Notebook dosyalarına ulaşmak için Github dizinine bakabilirsiniz.