Analisis Penjualan Toko Elektronik Online

Analisis Penjualan Toko Elektronik Online

·

21 min read

Apa kabar semuanya! Pada kesempatan kali ini kita akan membuat projek analisis penjualan toko elektronik online. Projek ini dibuat berdasarkan projek dari Keith Galli. Mengingat projek ini pada awalnya berbahasa inggris dan masih banyak hal yang bisa ditingkatkan seperti penulisan kode dan topik analisis, saya memutuskan untuk membuat ulang projek ini dengan menggunakan bahasa indonesia agar bisa menjangkau lebih banyak orang.

Di dalam projek ini kita akan mempelajari banyak topik seperti cara impor pustaka yang diperlukan, cara impor data dari file csv, membersihkan data (data cleaning) dan masih banyak lagi. Tanpa menunda-nunda lagi, mari kita mulai mengerjakan projek ini.

Tujuan dari projek ini

  • Mempelajari cara mengolah data csv.
  • Mempelajari teknik-teknik membersihkan data yang meliputi penanganan data yang hilang dan duplikat.
  • Menjawab berbagai pertanyaan bisnis yang sering ditemui seperti pendapatan bulanan dan produk yang paling laris.
  • Menvisualisasikan data untuk mendapatkan insight/informasi yang berharga.
  • Menulis kode yang lebih efisien dan mudah dimengerti.

Hal yang perlu dipersiapkan

  • Data
  • Jupyter Notebook/Jupyter Lab
  • Python
  • Pandas
  • Matplotlib
  • Kopi
  • Niat

Outline dari projek ini

  • Impor pustaka
  • Impor data
  • Informasi umum dari data
  • Pembersihan data
    • Menangani data yang hilang
    • Menangani kolom duplikat
    • Menangani indeks duplikat
    • Mengubah tipe data kolom ke tipe data yang benar
    • Mengurutkan baris-baris berdasarkan tanggal dalam urutan menurun
  • Analisis data eksploratif
    • Bulan apa yang memiliki penjualan terbanyak?
    • Kota apa yang memiliki penjualan terbanyak?
    • Jam berapa kita harus menampilkan iklan untuk memaksimalkan kemungkinan pelanggan membeli produk?
    • Produk apa yang sering dibeli bersamaan?
    • Produk apa yang paling laris? Menurutmu kenapa produk tersebut bisa selaris itu?

Impor pustaka

import os
import calendar
import jovian

from collections import Counter
from itertools import combinations

import pandas as pd
import matplotlib.pyplot as plt

Impor data

Karena kita mempunyai data penjualan selama 12 bulan dalam bentuk 12 file csv, kita akan menggabungkannya menjadi satu data untuk mempermudah analisis.

Langkah-langkah menggabungkan file csv:

  1. Lakukan loop untuk file-file csv.
  2. Buat dataframe untuk setiap file csv dan masukkan dataframe tersebut ke dalam list.
  3. Gabungkan dataframe-dataframe yang telah dibuat menjadi satu dataframe dengan menggunakan metode pd.concat().
all_months_sales_data = [pd.read_csv(file) for file in os.listdir() if file.endswith("csv")]
sales_data = pd.concat(all_months_sales_data)

Informasi umum dari data

Berikut ini merupakan informasi mengenai tipe data setiap kolom, jumlah kolom, jumlah baris dan penggunaan memori:

sales_data.info()

Dari informasi-informasi di atas kita bisa menyimpulkan bahwa data memiliki 186850 baris dan 6 kolom yang semuanya memiliki tipe data objek dengan penggunaan memori sekitar 10MB.

Pembersihan data

Menangani data yang hilang

Data yang hilang merupakan salah satu masalah yang paling sering ditemui di dalam dunia data science. Data yang hilang dapat menyebabkan banyak masalah yang sulit untuk dipecahkan nantinya jika kita membiarkannya begitu saja. Oleh karena itu, langkah ini seharusnya menjadi langkah yang paling pertama dilakukan agar kita tidak membuang waktu berharga kita untuk menemukan solusi mengapa kode tidak berjalan sama sekali atau tidak berjalan sesuai keinginan kita, hanya untuk mengetahui bahwa penyebabnya adalah data yang hilang. Cara termudah untuk menyelesaikan masalah ini adalah dengan menghapus baris yang memiliki data yang hilang.

Sebelum melakukan penghapusan, kita akan terlebih dahulu mencari baris mana yang memiliki data yang hilang dengan metode di bawah ini.

rows_with_nan = sales_data[sales_data.isna().any(axis=1)]
rows_with_nan

Dari output di atas, kita bisa melihat bahwa ada 545 baris yang memiliki nilai NaN yaitu indikator untuk data yang hilang.

Mari kita cek dulu jumlah baris yang ada sebelum melakukan penghapusan dengan menggunakan properti df.shape yang mengembalikan sebuah tuple berisi jumlah baris dan kolom. Proses ini akan sering kita lakukan untuk melihat apakah pembersihan data berhasil atau tidak.

sales_data.shape

Untuk menghapus baris yang memiliki nilai NaN, kita bisa menggunakan metode df.dropna().

sales_data = sales_data.dropna()

Berikut jumlah baris setelah penghapusan:

sales_data.shape

Setelah penghapusan, jumlah baris turun menjadi 186305.

Menangani kolom duplikat

Masalah ini biasanya terjadi ketika kita menggabungkan beberapa dataframe menjadi satu dataframe. Solusinya sama seperti masalah sebelumnya, yaitu dengan menghapus baris yang bersangkutan.

Berikut baris-baris yang memiliki kolom duplikat:

rows_with_dup_cols = sales_data[sales_data["Order ID"] == "Order ID"]
rows_with_dup_cols

Ternyata kita memiliki cukup banyak baris yang memiliki kolom duplikat, yaitu sebanyak 355 baris.

Berikut jumlah baris sebelum penghapusan:

sales_data.shape

Untuk menghapus baris yang bermasalah, caranya sangat simpel yaitu dengan cara menfilter baris yang tidak memiliki nama kolom.

sales_data = sales_data[sales_data["Order ID"] != "Order ID"]

Berikut jumlah baris setelah penghapusan:

sales_data.shape

Setelah penghapusan, jumlah baris turun menjadi 185950.

Menangani indeks duplikat

Masalah ini juga sering muncul setelah menggabungkan beberapa dataframe menjadi satu dataframe.

Mari kita cek apakah data memiliki indeks duplikat atau tidak.

sales_data.iloc[0]

Kita bisa melihat dari output di atas, ada banyak baris yang memiliki indeks 0, hal ini tidak seharusnya terjadi karena indeks bersifat unik untuk setiap baris. Cara lain untuk mengecek apakah data memiliki indeks duplikat atau tidak adalah dengan mengecek indeks terakhir. Indeks mulai dari 0, jadi indeks terakhir harusnya bernilai jumlah baris - 1, yaitu 185949.

sales_data.loc[len(sales_data) - 1]

Kita mendapat KeyError yang berarti tidak ada indeks yang bersangkutan di dalam data. Mari kita lihat lima baris terakhir untuk mengetahui nilai indeks terakhir.

sales_data.tail()

Ternyata nilai indeks terakhir adalah 9722, hal ini tentunya tidak masuk akal karena data memiliki jumlah baris 185950, jadi seharusnya nilai indeks terakhir yang benar adalah 185950 - 1 = 185949. Solusi dari masalah ini adalah dengan mereset indeks menjadi seperti semula menggunakan metode pd.reset_index().

# We have to pass a drop parameter with the value of True to the method so pandas doesn't add an index column to the dataframe.
sales_data = sales_data.reset_index(drop=True)

Mari kita cek lagi apakah indeks sudah normal atau tidak.

sales_data.iloc[0]
sales_data.tail()

Hanya ada 1 baris yang memiliki indeks 0 dan nilai indeks terarkhir adalah 185949 yang berarti masalah ini akhirnya selesai.

Mengubah tipe data kolom ke tipe data yang benar

Semua data yang kita miliki masih bertipe objek. Jadi untuk melakukan analisis dengan lancar kita harus terlebih dahulu mengubahnya ke tipe data yang benar.

Berikut tipe data pada setiap kolom sebelum proses perubahan:

sales_data.dtypes

Kolom "Quantity Ordered" dan "Price Each" merupakan data numerik, jadi harus diubah menjadi tipe data numerik agar operasi-operasi matematika dapat dilakukan pada kolom tersebut. Cara yang pertama adalah dengan meggunakan metode astype(), kekurangan dari metode ini adalah kita harus memberi tahu pandas secara manual jenis data numerik apa yang kita inginkan dengan memasukkan nilai "int"/"float" sebagai argumen metode tersebut. Kita bisa membuat proses ini jauh lebih mudah menggunakan metode pd.to_numeric() sehingga proses pengubahan tipe data dilakukan secara otomatis oleh pandas.

Kolom "Order Date" merupakan data tanggal. Untuk mengakses tanggal dari kolom tersebut tanpa mengubah tipe datanya menjadi datetime, kita bisa mengakses properti str dan memotong bagian dari string yang kita perlukan, namun cara ini dianggap sebagai cara yang "hacky" dan cukup rumit. Cara yang lebih mudah adalah dengan menggunakan metode pd.to_datetime(), perlu dicatat bahwa metode ini membutuhkan waktu yang agak lama untuk selesai tergantung dari seberapa besar data yang dimiliki. Di belakang, pandas menggunakan algoritma pintar untuk membaca tanggal dari string tersebut. Setelah mengubahnya ke tipe data datetime, kita bisa mengakses semua bagian tanggal seperti bulan, tahun, jam, dan lainnya menggunakan properti dt.

Mengubah tipe data menjadi tipe data numerik

sales_data["Quantity Ordered"] = pd.to_numeric(sales_data["Quantity Ordered"])
sales_data["Price Each"] = pd.to_numeric(sales_data["Price Each"])

Mengubah tipe data menjadi tipe data datetime

sales_data["Order Date"] = pd.to_datetime(sales_data["Order Date"])

Berikut tipe data setiap kolom setelah proses perubahan:

sales_data.dtypes

Dari output di atas, tipe data "Quantity Ordered" berubah menjadi int64, sedangkan tipe data "Price Each" berubah menjadi float64. Kolom "Order Date" berubah menjadi datetime64.

Mengurutkan baris berdasarkan tanggal dengan urutan menurun

Dengan mengurutkan baris berdasarkan tanggal, kita bisa melihat dengan mudah penjualan terbaru.

# We have to reset the index again as the rows is moved from its default position
sales_data = sales_data.sort_values(by="Order Date", ascending=False).reset_index(drop=True)

Analisis data eksploratif

Pertanyaan 1: Bulan apa yang memiliki penjualan terbanyak?

Untuk menjawab pertanyaan ini, kita membutuhkan informasi penjualan (sales) dan informasi bulan sehingga kita harus membuat dua kolom baru.

Membuat kolom "Sales"

sales_data["Sales"] = sales_data["Quantity Ordered"] * sales_data["Price Each"]

Memindahkan kolom "Sales" ke samping kolom "Price Each"

# Function by normanius from https://stackoverflow.com/questions/25122099/move-column-by-name-to-front-of-table-in-pandas
def move_column_inplace(df, col, pos):
    col = df.pop(col)
    df.insert(pos, col.name, col)

move_column_inplace(sales_data, "Sales", 4)

Membuat kolom "Month"

sales_data["Month"] = sales_data["Order Date"].dt.month

Memindahkan kolom "Month" ke samping kolom "Order Date"

move_column_inplace(sales_data, "Month", 6)

Berikut penampilan dataframe setelah menambahkan kolom "Sales" dan "Month":

sales_data

Penjualan perbulan

month_group = sales_data.groupby("Month")
monthly_sales = month_group.sum()["Sales"]
monthly_sales

Visualisasi penjualan perbulan

months = [calendar.month_name[month_num] for month_num, months in month_group]

plt.bar(months, monthly_sales)
plt.xticks(months, rotation="vertical")
plt.xlabel("Month")
plt.ylabel("Sales in million $US")
plt.show()

Dari visualisasi di atas, bisa disimpulkan bahwa bulan Desember adalah bulan dengan penjualan terbanyak, menghasilkan $4.6 juta.

Penjelasan:

  1. Natal, salah satu liburan yang paling ditunggu, waktu dimana orang-orang memberikan hadiah kepada pasangan, anak, orang tua dan teman sehingga permintaan barang makin banyak.
  2. Banyak orang yang menabung uang dari awal tahun sampai akhir tahun demi membeli barang yang mereka inginkan ditambah lagi dengan banyaknya diskon di bulan Desember sehingga faktor gabungan ini menambah angka penjualan secara drastis.

Pertanyaan 2: Kota apa yang memiliki penjualan terbanyak?

Membuat kolom "City"

def get_city(address):
    city = address.split(", ")[1]
    return city

def get_state(address):
    state = address.split(", ")[2][0:2]
    return state

sales_data["City"] = sales_data["Purchase Address"].apply(lambda x: f"{get_city(x)} ({get_state(x)})")

Berikut penampilan data setelah menambahkan kolom "City":

Penjualan perkota

city_group = sales_data.groupby("City")
sales_by_city = city_group.sum()["Sales"]
sales_by_city

Visualisasi penjualan perkota

cities = [city for city, cities in city_group]

plt.bar(cities, sales_by_city)
plt.xticks(cities, rotation="vertical")
plt.xlabel("City")
plt.ylabel("Sales in million $US")
plt.show()

Kota San Francisco memiliki penjualan terbanyak. Penjelasan: Kota San Francisco merupakan salah satu pusat industri teknologi di US. San Francisco merupakan rumah dari perusahaan-perusahaan terkenal seperti Apple, Google, Facebook dan Twitter, serta startup teknologi lainnya. San Francisco sekarang dianggap sebagai kota yang paling penting bagi startup teknologi yang terus berkembang. Jadi tidak mengejutkan kalau permintaan teknologi di kota ini sangat tinggi.

Pertanyaan 3: Jam berapa kita harus menampilkan iklan untuk memaksimalkan kemungkinan pelanggan membeli produk?

Membuat kolom "Hour"

sales_data["Hour"] = sales_data["Order Date"].dt.hour

Memindahkan kolom "Hour" ke samping kolom "Month"

move_column_inplace(sales_data, "Hour", 7)

Berikut penampilan data setelah menambahkan kolom "Hour":

Jumlah pesanan perjam

hour_group = sales_data.groupby("Hour")
hourly_orders = hour_group.count()["Quantity Ordered"]
hourly_orders

Visualisasi jumlah pesanan perjam

hours = [hour for hour, hours in hour_group]

plt.figure(figsize=(10,5))
plt.plot(hours, hourly_orders)
plt.xticks(hours)
plt.xlabel("Hour")
plt.ylabel("Number of order")
plt.grid()
plt.show()

Ada beberapa insights yang bisa kita dapatkan dari visualisasi ini yaitu:

  1. Jumlah pesanan yang tinggi terjadi pada jam 11:00-13:00 (memuncak pada jam 12:00). Penjelasan: Jam 11:00-13:00 merupakan waktu bagi mayoritas orang istirahat makan siang sehingga mereka mempunyai waktu kosong untuk melakukan pemesanan.
  2. Jumlah pesanan yang tinggi juga terjadi pada jam 18:00-22:00 (memuncak pada jam 19:00). Penjelasan: Rata-rata orang telah pulang dari kerja, mereka mungkin sudah menyelesaikan semua urusan mereka dan sedang bersantai.
  3. Jumlah pesanan yang rendah terjadi pada jam 00:00-07:00 (puncak terendah pada jam 03:00-04:00). Penjelasan: Rata-rata orang masih tidur pada jam tersebut.
  4. Jumlah pesanan menurun secara drastis pada jam 20:00-04:00, naik secara drastis pada jam 05:00-12:00, menurun lagi pada jam 13:00-15:00 dan naik lagi pada jam 16:00-19:00.

Kesimpulan: Waktu terbaik untuk menampilkan iklan adalah pada jam 11:00-13:00 (waktu istirahat kerja) dan 18:00-20:00 (waktu santai setelah pulang kerja). Waktu terburuk untuk menampilkan iklan adalah pada jam 21:00-07:00 (waktu tidur)

Pertanyaan 4: Produk apa yang sering dibeli bersamaan?

Setiap pesanan baik satu produk maupun beberapa produk mempunyai Order ID yang unik, hal ini berarti jika produk A dan produk B memiliki Order ID yang sama berarti produk-produk tersebut dibeli bersamaan. Kita akan membuat sebuah tabel baru dengan kolom "Order ID" dan kolom "Products" yang berisi produk-produk yang memiliki Order ID yang sama.

rows_with_duplicate_orderid = sales_data[sales_data["Order ID"].duplicated(keep=False)]
rows_with_duplicate_orderid["Products"] = rows_with_duplicate_orderid.groupby("Order ID")["Product"].transform(lambda x: ",".join(x))
rows_with_duplicate_orderid = rows_with_duplicate_orderid[["Order ID", "Products"]].drop_duplicates()
rows_with_duplicate_orderid

Setelah berhasil membuat tabel yang baru, kita bisa menyelesaikan kasus ini dengan menerapkan sebuah konsep matematika yaitu kombinasi dengan cara mencari frekuensi kemunculan kombinasi n produk.

Berikut daftar frekuensi kombinasi 2 produk yang dibeli bersamaan:

count = Counter()

for row in rows_with_duplicate_orderid["Products"]:
    row_list = row.split(",")
    count.update(Counter(combinations(row_list, 2)))

count.most_common()

Dari output di atas, bisa disimpulkan bahwa Iphone dan Lighting Charging Cable adalah 2 produk yang paling sering dibeli bersamaan.

Berikut daftar frekuensi kombinasi 3 produk yang dibeli bersamaan:

count = Counter()

for row in rows_with_duplicate_orderid["Products"]:
    row_list = row.split(",")
    count.update(Counter(combinations(row_list, 3)))

count.most_common()

Dari output di atas, bisa disimpulkan bahwa Google Phone, USB-C Charging Cable dan Wired Headphones adalah 3 produk yang paling sering dibeli bersamaan.

Pertanyaan 5: Produk apa yang paling laris? Menurutmu kenapa produk tersebut bisa selaris itu?

Cara untuk mengetahui produk yang paling laris adalah dengan cara mengelompokkan dataframe berdasarkan kolom produk dan jumlahkan kuantitas yang dipesan untuk setiap grup produk.

product_group = sales_data.groupby("Product")
quantity_ordered = product_group["Quantity Ordered"].sum()
quantity_ordered

Visualisasi

products = [product for product, products in product_group]

plt.figure(figsize=(10,5))
plt.bar(products, quantity_ordered)
plt.xticks(products, rotation="vertical")
plt.xlabel("Products")
plt.ylabel("Quantity Ordered")
plt.show()

Produk yang paling laris adalah AAA batteries (4-pack). Alasannya karena baterai harganya yang sangat murah dan biasanya dibeli dalam jumlah banyak, untuk membuktikan hipotesis ini, kita bisa membuat sebuah grafik yang menunjukkan korelasi antara harga dan jumlah pesanan.

prices = product_group["Price Each"].mean()

fig, ax1 = plt.subplots()

ax2 = ax1.twinx()
ax1.bar(products, quantity_ordered, color="lightblue")
ax2.plot(products, prices, "b-", color="orange")

ax1.set_xlabel("Products")
ax1.set_ylabel("Quantity Ordered", color="lightblue")
ax2.set_ylabel("Price ($)", color="orange")
ax1.set_xticklabels(products, rotation="vertical")

plt.show()

Sekian dari artikel saya. Semoga saja artikel ini bisa bermanfaat bagi banyak orang.

Ayo likes dan bagikan artikel ini ke temanmu agar semakin banyak orang yang terbantu dengan informasi ini! Sampai jumpa lagi di artikel saya yang selanjutnya!