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. İlk olarak veriyi okutarak ve boyutlarına bakarak başlayalım. Veriyi indirmek için tıklayınız.
In [1]:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# İ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)))
1
Veri çerçevesinin boyutu: (541909, 8)
Veride 8 kolon var. Kolonlar hakkındaki ilk bilgiyi head()
fonksiyonuyla görebiliriz.
In [2]:
1
2
HTML(df.head().to_html()) #bu satır sorunlu olduğu için aşağıdaki satırla alabilirsiniz.
display(df)
Out[2]:
InvoiceNo | StockCode | Description | Quantity | InvoiceDate | UnitPrice | CustomerID | Country | |
---|---|---|---|---|---|---|---|---|
0 | 536365 | 85123A | WHITE HANGING HEART T-LIGHT HOLDER | 6 | 2010-12-01 08:26:00 | 2.55 | 17850.0 | United Kingdom |
1 | 536365 | 71053 | WHITE METAL LANTERN | 6 | 2010-12-01 08:26:00 | 3.39 | 17850.0 | United Kingdom |
2 | 536365 | 84406B | CREAM CUPID HEARTS COAT HANGER | 8 | 2010-12-01 08:26:00 | 2.75 | 17850.0 | United Kingdom |
3 | 536365 | 84029G | KNITTED UNION FLAG HOT WATER BOTTLE | 6 | 2010-12-01 08:26:00 | 3.39 | 17850.0 | United Kingdom |
4 | 536365 | 84029E | RED WOOLLY HOTTIE WHITE HEART. | 6 | 2010-12-01 08:26:00 | 3.39 | 17850.0 | United Kingdom |
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.
In [3]:
1
2
# 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.
In [4]:
1
2
3
print("Ülkeler")
print(df_country.groups.keys())
print("Ülke sayısı: " + str(df_country.ngroups))
1
2
3
4
5
Ülkeler
dict_keys(['Australia', 'Austria', 'Bahrain', 'Belgium', 'Brazil', 'Canada', 'Channel Islands', 'Cyprus', 'Czech Republic', 'Denmark', 'EIRE', 'European Community', 'Finland', 'France', 'Germany', 'Greece', 'Hong Kong', 'Iceland', 'Israel', 'Italy', 'Japan', 'Lebanon', 'Lithuania', 'Malta', 'Netherlands', 'Norway', 'Poland', 'Portugal', 'RSA', 'Saudi Arabia', 'Singapore', 'Spain', 'Sweden', 'Switzerland', 'USA', 'United Arab Emirates', 'United Kingdom', 'Unspecified'])
Ülke sayısı: 38
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.
In [5]:
1
2
3
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.
In [6]:
1
HTML(df_country.get_group('Austria').head().to_html())
Out[6]:
InvoiceNo | StockCode | Description | Quantity | InvoiceDate | UnitPrice | CustomerID | Country | |
---|---|---|---|---|---|---|---|---|
31464 | C538971 | 22153 | ANGEL DECORATION STARS ON DRESS | -48 | 2010-12-15 11:39:00 | 0.42 | 12865.0 | Austria |
34293 | 539330 | 37449 | CERAMIC CAKE STAND + HANGING CAKES | 8 | 2010-12-17 09:38:00 | 8.50 | 12370.0 | Austria |
34294 | 539330 | 37446 | MINI CAKE STAND WITH HANGING CAKES | 8 | 2010-12-17 09:38:00 | 1.45 | 12370.0 | Austria |
34295 | 539330 | 22962 | JAM JAR WITH PINK LID | 12 | 2010-12-17 09:38:00 | 0.85 | 12370.0 | Austria |
34296 | 539330 | 21428 | SET3 BOOK BOX GREEN GINGHAM FLOWER | 4 | 2010-12-17 09:38:00 | 4.25 | 12370.0 | Austria |
Ş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.
In [7]:
1
2
df_country_product = df.groupby(by = ['Country', 'StockCode'])['Quantity'].sum()
print(df_country_product.head())
1
2
3
4
5
6
7
8
9
10
11
12
13
Country StockCode
Australia 15036 600
20665 6
20675 216
20676 216
20677 216
Name: Quantity, dtype: int64
Dataframe yapısını korumak için reset_index()
fonksiyonunu kullanabiliriz.
In [8]:
1
2
df_country_product = df_country_product.reset_index()
HTML(df_country_product.head().to_html())
Out[8]:
Country | StockCode | Quantity | |
---|---|---|---|
0 | Australia | 15036 | 600 |
1 | Australia | 20665 | 6 |
2 | Australia | 20675 | 216 |
3 | Australia | 20676 | 216 |
4 | Australia | 20677 | 216 |
Ü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.
In [9]:
1
2
3
idx = df_country_product.groupby(['Country'])['Quantity'].transform(max) == df_country_product['Quantity']
HTML(df_country_product[idx].head(10).to_html())
Out[9]:
Country | StockCode | Quantity | |
---|---|---|---|
221 | Australia | 22492 | 2916 |
671 | Austria | 21918 | 288 |
914 | Bahrain | 23076 | 96 |
1005 | Belgium | 21212 | 480 |
1705 | Brazil | 21430 | 24 |
1714 | Brazil | 22630 | 24 |
1716 | Brazil | 22697 | 24 |
1717 | Brazil | 22698 | 24 |
1718 | Brazil | 22699 | 24 |
1719 | Brazil | 22722 | 24 |
Ş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.
In [10]:
1
2
3
4
5
6
7
8
9
10
# 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())
1
2
3
Temizlik öncesi alışveriş sayısı: 541909
Temizlik sonrası alışveriş sayısı: 406829
Out[10]:
InvoiceNo | StockCode | Description | Quantity | InvoiceDate | UnitPrice | CustomerID | Country | Amount | |
---|---|---|---|---|---|---|---|---|---|
0 | 536365 | 85123A | WHITE HANGING HEART T-LIGHT HOLDER | 6 | 2010-12-01 08:26:00 | 2.55 | 17850.0 | United Kingdom | 15.30 |
1 | 536365 | 71053 | WHITE METAL LANTERN | 6 | 2010-12-01 08:26:00 | 3.39 | 17850.0 | United Kingdom | 20.34 |
2 | 536365 | 84406B | CREAM CUPID HEARTS COAT HANGER | 8 | 2010-12-01 08:26:00 | 2.75 | 17850.0 | United Kingdom | 22.00 |
3 | 536365 | 84029G | KNITTED UNION FLAG HOT WATER BOTTLE | 6 | 2010-12-01 08:26:00 | 3.39 | 17850.0 | United Kingdom | 20.34 |
4 | 536365 | 84029E | RED WOOLLY HOTTIE WHITE HEART. | 6 | 2010-12-01 08:26:00 | 3.39 | 17850.0 | United Kingdom | 20.34 |
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.
In [11]:
1
2
3
4
5
6
7
df_customer = df.groupby(['CustomerID', 'InvoiceNo']).agg({'StockCode':'nunique',
'Amount':'sum',
'InvoiceDate': 'max'}).reset_index()
HTML(df_customer.head().to_html())
Out[11]:
CustomerID | InvoiceNo | StockCode | Amount | InvoiceDate | |
---|---|---|---|---|---|
0 | 12346.0 | 541431 | 1 | 77183.60 | 2011-01-18 10:01:00 |
1 | 12346.0 | C541433 | 1 | -77183.60 | 2011-01-18 10:17:00 |
2 | 12347.0 | 537626 | 31 | 711.79 | 2010-12-07 14:57:00 |
3 | 12347.0 | 542237 | 29 | 475.39 | 2011-01-26 14:30:00 |
4 | 12347.0 | 549222 | 24 | 636.25 | 2011-04-07 10:43:00 |
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.
In [12]:
1
2
3
4
5
6
7
8
9
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())
Out[12]:
CustomerID | Number_of_Transactions | Total_Amount | Average_Amount | Last_Transaction_Date | |
---|---|---|---|---|---|
0 | 12346.0 | 2 | 0.00 | 0.000000 | 2011-01-18 10:17:00 |
1 | 12347.0 | 7 | 4310.00 | 615.714286 | 2011-12-07 15:52:00 |
2 | 12348.0 | 4 | 1797.24 | 449.310000 | 2011-09-25 13:13:00 |
3 | 12349.0 | 1 | 1757.55 | 1757.550000 | 2011-11-21 09:51:00 |
4 | 12350.0 | 1 | 334.40 | 334.400000 | 2011-02-02 16:01:00 |
groupby()
fonksiyonunu kullanarak veriyi özetledik. Bu noktadan sonra uygulamanıza göre veriden özetlediğiniz bilgileri kullanabilirsiniz.