Daha önceki yazımızda bir veri bilimcinin yolculuğunu 4 ana
adıma ayırmıştık:
Keşif, Modelleme, Kodlama ve Sunum.
Bu yolculukta en çok vakit geçirdiğimiz, belki de en heyecanlı
durağın Keşif ve Analiz olduğundan bahsetmiştik.
Hani o eldeki dağınık veriye bakıp “Peki, şimdi ne yapacağız?”
dediğimiz an var ya? İşte orası.
Bu seride, bu adımların her birini birlikte, uygulamalı olarak
geçeceğiz.
Kemerleri bağlayın 🚀 çünkü bugün elimizdeki bir yığın müşteri şikayet
verisinin içine dalıyoruz ve o karmaşadan anlamlı bir
harita çıkarmaya çalışacağız.
Düşünün ki bir e-ticaret şirketinde çalışıyoruz ve
yöneticimiz elinde bir Excel dosyasıyla geldi:
“İşte son 6 ayın müşteri şikayetleri. Buna bir bakın, ne
yapabiliriz?” dedi.
Çoğumuzun ilk tepkisi hemen kod yazmaya ya da
en havalı algoritmaları denemeye atlamak
olabilir.
Ama durun! Pusulayı ayarlamadan yola çıkarsak
kayboluruz.
İlk işimiz, okyanusun ortasında ne aradığımızı bilmek: Doğru soruyu sormak.
👉 Biz bu yazıda, bu sorulardan ilkine odaklanalım:
Şikayetlerin müşteri memnuniyeti ve kaybı üzerindeki etkisini
anlayabilir miyiz?
Bu soruyu aklımızın bir köşesine yazdık. Artık yola çıkabiliriz.
Elimizde veri var. Panik yok. Ama ham veri
genellikle biraz… “dağınıktır”.
Tıpkı bir yemeğe başlamadan önce sebzeleri yıkamak ve ayıklamak gibi,
biz de verimizi analize hazır hale getirmeliyiz.
Analizimizi sabote edebilecek en büyük sorunlardan biri eksik
veridir (NA).
Önce veri setimizde hiç eksik değer olup olmadığını kontrol edelim.
Bunun en basit yolu, her sütundaki eksik değerleri saydırmaktır. Biz
kodlarımızı R yazılım ile yazalım:
# 1. Veri setini yükle (UTF-8 kodlamasıyla)
veri <- read.csv("data/musteri_sikayetleri.csv")
# Sütunlardaki eksik değer sayısını kontrol edelim
colSums(is.na(veri))
## sikayet_id musteri_id sikayet_tarihi sikayet_kategorisi
## 0 0 0 0
## sikayet_metni
## 0
Bu komutun çıktısı her sütun için 0 ise,
harika!
Hiç eksik verimiz yok demektir. Eğer sıfırdan farklı bir sayı görseydik,
o sütun üzerinde ne yapacağımıza (satırları silmek, veriyi doldurmak
vb.) karar vermemiz gerekecekti.
Neyse ki bizim verimiz temiz görünüyor! 🎉
Şimdi str()
veya glimpse()
komutlarıyla
verimizin yapısına bir göz atalım.
Her sütunun hangi tipte olduğunu bilmek, analiz
sırasında yanlışlık yapmamızı önler.
# Veri tiplerine göz atalım
#str(veri)
# Alternatif olarak dplyr paketi ile glimpse() yapalım. dplyr paketine alışalım.
library(dplyr)
glimpse(veri)
## Rows: 500
## Columns: 5
## $ sikayet_id <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, …
## $ musteri_id <int> 1049, 1065, 1074, 1146, 1122, 1049, 1128, 1047, 102…
## $ sikayet_tarihi <chr> "2024-01-13", "2024-04-07", "2024-02-10", "2024-06-…
## $ sikayet_kategorisi <chr> "Teslimat Gecikmesi", "Ürün Hasarlı Geldi", "Ürün H…
## $ sikayet_metni <chr> "Teslimat tarihi geçti ama ürünüm ortada yok.", "Ür…
Çıktıda iki önemli nokta gözümüze çarpıyor:
sikayet_id
ve musteri_id
sayısal (int) görünüyor, ama aslında onlar birer
etiket.
Onlarla matematiksel işlem yapmayacağız, bu yüzden faktör
(factor) veya karakter (character) tipine
çevirmeliyiz.
sikayet_tarihi
bir metin (chr)
olarak duruyor.
Bunu R’ın anlayacağı Date formatına çevirmeliyiz ki
zamanla ilgili analizler yapabilelim.
Haydi bu pürüzleri giderelim!
lubridate
paketi, tarih ve saat
işlemleri için bir harikadır!
Hadi verimizi hem ID’ler hem de tarih sütunu açısından temizleyelim.
# Paketi yükleyelim
library(lubridate)
# Adım 3.1: Anlamsız ID'leri metin formatına çeviriyoruz
veri$sikayet_id <- as.character(veri$sikayet_id)
veri$musteri_id <- as.character(veri$musteri_id)
# Adım 3.2: Tarih formatındaki metni, gerçek bir 'Date' objesine çeviriyoruz
# ymd() fonksiyonu "Yıl-Ay-Gün" formatını otomatik olarak tanır
veri$sikayet_tarihi <- ymd(veri$sikayet_tarihi)
# Son bir kontrol: veri tipleri doğru mu?
print("Veri tipleri düzeltildikten sonraki son durum:")
## [1] "Veri tipleri düzeltildikten sonraki son durum:"
glimpse(veri)
## Rows: 500
## Columns: 5
## $ sikayet_id <chr> "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", …
## $ musteri_id <chr> "1049", "1065", "1074", "1146", "1122", "1049", "11…
## $ sikayet_tarihi <date> 2024-01-13, 2024-04-07, 2024-02-10, 2024-06-19, 20…
## $ sikayet_kategorisi <chr> "Teslimat Gecikmesi", "Ürün Hasarlı Geldi", "Ürün H…
## $ sikayet_metni <chr> "Teslimat tarihi geçti ama ürünüm ortada yok.", "Ür…
Grafiğimizin düzgün gözükmesi için ufak bir değişiklik
# dplyr ve stringr kütüphanelerinin yüklü olduğundan emin olalım
# (genellikle tidyverse içinde gelirler)
library(dplyr)
library(stringr)
# "sikayet_kategorisi" sütunundaki Türkçe karakter sorununu düzeltiyoruz
veri <- veri %>%
mutate(sikayet_kategorisi = str_replace(sikayet_kategorisi, "İade Süreci", "Iade Sureci")) %>%
mutate(sikayet_kategorisi = str_replace(sikayet_kategorisi, "Ürün Hasarlı Geldi", "Urun Hasarli Geldi"))
# Değişikliğin başarılı olup olmadığını kontrol edelim.
# Bu komut, sütundaki tüm benzersiz kategorileri listeler.
print("Kategori isimleri güncellendi mi?")
## [1] "Kategori isimleri güncellendi mi?"
unique(veri$sikayet_kategorisi)
## [1] "Teslimat Gecikmesi" "Urun Hasarli Geldi" "Fatura Sorunu"
## [4] "Teknik Destek" "Iade Sureci"
Binlerce satır veriye bakarak bir desen görmek imkansıza
yakındır.
Ama iyi bir grafik, binlerce satırın anlatamadığı hikayeyi tek
bir bakışta anlatabilir.
Haydi, şikayet verilerimizi konuşturmaya başlayalım!
İlk olarak, şikayetlerin hangi kategorilerde toplandığını merak
ederiz.
“Fatura”, “Teslimat Gecikmesi”, “Ürün Hasarlı Geldi”, “Teknik Destek”
gibi kategorilerimiz olduğunu varsayalım.
# Gerekli paket
library(ggplot2)
ggplot(veri, aes(x = fct_infreq(sikayet_kategorisi))) +
geom_bar(fill = "#FF6347") +
labs(title = "Sikayetlerin Kategorilere Gore Dagilimi",
x = "Sikayet Kategorisi",
y = "Sikayet Sayisi") +
theme_minimal() +
coord_flip() # Kategoriler uzunsa yatay göstermek daha okunaklı olur
Aha! Grafiğe baktığımızda, “Teslimat Gecikmesi”nin
açık ara en büyük sorun olduğunu gördük.
İşte bu, odaklanmamız gereken ilk yer olabilir.
Peki bu şikayetler hep mi böyleydi, yoksa belli dönemlerde mi
artıyor?
Özel bir kampanya dönemi veya yeni bir kargo firmasıyla anlaştığımız
tarih işleri karıştırmış olabilir mi?
Bunu anlamak için şikayetleri zamana yayarak
inceleyelim.
library(lubridate)
veri %>%
mutate(sikayet_tarihi = as.Date(sikayet_tarihi)) %>%
count(sikayet_tarihi) %>%
ggplot(aes(x = sikayet_tarihi, y = n)) +
geom_line(color = "#4682B4") +
labs(title = "Zaman Icinde Gunluk Sikayet Sayisi",
x = "Tarih",
y = "Sikayet Sayisi") +
theme_minimal()
Bazen kategoriler yeterli olmaz.
Müşterilerin kendi cümlelerinde en çok hangi kelimeleri kullandığını
görmek, sorunun kökünü anlamamıza yardımcı olabilir.
Şikayet metinlerinden bir kelime bulutu
oluşturalım.
library(wordcloud)
library(tidytext)
library(dplyr)
# 1. Kendi basit Türkçe stop words listemizi oluşturuyoruz
turkce_stop_words <- tibble(word = c("bir", "ve", "ile", "ama", "için", "gibi", "olarak",
"da", "de", "bu", "çok", "daha", "kadar", "ben",
"ne", "var", "yok", "sonra", "önce", "tarafından"))
# 2. Kelimeleri ayırıp, Türkçe stop words listemizi çıkarıyoruz
sikayet_metinleri <- veri %>%
# Veri setinizde metin içeren sütunun adının 'sikayet_metni' olduğundan emin olun
unnest_tokens(word, sikayet_metni) %>%
anti_join(turkce_stop_words) %>%
count(word, sort = TRUE)
# 3. Kelime bulutunu oluşturuyoruz
wordcloud(words = sikayet_metinleri$word,
freq = sikayet_metinleri$n,
max.words = 100,
random.order = FALSE,
rot.per = 0.35,
colors = brewer.pal(8, "Dark2"))
Şikayet Metinlerinde En Sık Geçen Kelimeler
Bu kelime bulutu, bize şikayet eden müşterinin adeta bir portresini
çiziyor.
En büyük kelimeler olan “bekliyorum”,
“istiyorum” ve “acil”,
müşterilerimizin sabırsızlıkla bir çözüm aradığını ve sürecin bir
yerinde takılıp kaldığını gösteriyor.
Peki ne hakkında bekliyorlar? İkinci plandaki kelimeler sorunun
kaynağını işaret ediyor: “ürün”,
“cihaz”, “defolu” ve
“kırık”.
Anlıyoruz ki, şikayetlerin büyük bir kısmı fiziksel ürün problemleriyle
ilgili.
Tüm bu süreçte en çok aradıkları şey ise “bilgi”.
Müşteriler, ne yapacaklarını veya süreçlerinin ne durumda olduğunu
öğrenmek istiyor.
Özetle, müşterilerimiz bize diyor ki:
“Defolu veya kırık ürünümle ilgili sizden acil bir çözüm ve bilgi
bekliyorum, ama hala bir sonuç alamadım.”
Bu bulut, operasyonel olarak hangi noktalara odaklanmamız gerektiğini net bir şekilde ortaya koyuyor.
Bu kelime bulutu bize harika bir hikaye anlatırken, dikkatli gözler bir detayı fark etmiş olabilir. oldu.unu veya k.r.k gibi biraz garip görünen kelimeler, bize veri temizliğinin neden hiç bitmeyen bir süreç olduğunu hatırlatıyor. Bunun sebebi, metinleri kelimelere ayırırken tüm noktalama işaretlerini temizlememiş olmamız.
Bir sonraki metin analizimizde, kelimelere ayırma işleminden önce tüm noktaları, virgülleri temizleyen bir adım eklersek, bulutumuzun çok daha net ve anlamlı hale geldiğini göreceğiz. Her proje bize böyle küçük ama değerli dersler öğretir!
Pusulamızı ayarladık ve haritamızdaki ilk işaretleri koyduk. Artık elimizde sadece veri yok; üzerinde konuşabileceğimiz, aksiyon alabileceğimiz bilgiler var.
Bu bilgilerle geleceği tahmin edebilir miyiz?
Yani, bir müşterinin şikayetine bakarak onun bizi terk edip etmeyeceğini
öngörebilir miyiz?
İşte bu sorunun cevabı, yolculuğumuzun bir sonraki durağı olan Modelleme’de gizli.
Bir sonraki yazıda görüşmek üzere, veriyle kalın! ✨