-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.py
More file actions
2206 lines (1779 loc) · 62.2 KB
/
script.py
File metadata and controls
2206 lines (1779 loc) · 62.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# %% [markdown]
# <a target="_blank" href="https://colab.research.google.com/github/fxrdhan/Data-Analytics-Project/blob/main/notebook.ipynb">
# <img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/>
# </a>
#
# %% [markdown]
# # Proyek Analisis Data: E-Commerce Public Dataset
#
# - **Nama:** Firdaus Arif Ramadhani
# - **Email:** firdausarief65@gmail.com
# - **ID Dicoding:** 2VX3464E3ZYQ
#
# %% [markdown]
# ## Menentukan Pertanyaan Bisnis
#
# %% [markdown]
# 1. Kategori produk apa saja yang paling laris?
# 2. Apa faktor utama yang menyebabkan pembatalan pesanan?
# 3. Bagaimana pengaruh interval pengiriman terhadap tingkat kepuasan pelanggan?
# 4. Bagaimana performa berbagai kategori produk dalam hal kepuasan pelanggan?
# 5. Bagaimana tren penjualan bulanan?
#
# %% [markdown]
# ## Import Semua Packages/Library yang Digunakan
#
# %%
import random
import re
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from collections import Counter
from deep_translator import GoogleTranslator as Translator
from wordcloud import WordCloud
# %% [markdown]
# ## Data Wrangling
#
# %% [markdown]
# ### Gathering Data
#
# %% [markdown]
# #### Data Tabel `products_df`
#
# %%
products_df = pd.read_csv(
"https://media.githubusercontent.com/media/fxrdhan/Data-Analysis-Project/refs/heads/main/e-commerce_public_dataset/products_dataset.csv"
)
products_df.head()
# %% [markdown]
# **Insight:**\
# Dataset products_df berisi informasi terkait produk.\
# Informasi yang tersedia diantaranya:
#
# 1. `product_id`: ID unik untuk setiap produk.
# 2. `product_category_name`: Panjang nama produk dalam karakter.
# 3. `product_name_lenght`: Panjang deskripsi produk.
# 4. `product_photos_qty`: Jumlah foto yang tersedia untuk produk.
# 5. `product_weight_g`: Berat produk.
# 6. `product_length_cm`, `product_height_cm`, dan `product_width_cm`: DImensi produk.
#
# %% [markdown]
# #### Data Tabel `product_category_translation_df`
#
# %%
product_category_translation_df = pd.read_csv(
"https://media.githubusercontent.com/media/fxrdhan/Data-Analysis-Project/refs/heads/main/e-commerce_public_dataset/product_category_name_translation.csv"
)
product_category_translation_df.head()
# %% [markdown]
# **Insight:**\
# Dataset `product_category_translation_df` memuat terjemahan nama kategori produk dari bahasa Portugis ke bahasa Inggris.\
# Informasi yang tertera diantaranya:
#
# 1. `product_category_name`: Nama kategori dalam bahasa Portugis.
# 2. `product_category_name_english`: Nama kategori dalam bahasa Inggris.
#
# %% [markdown]
# #### Data Tabel `order_reviews_df`
#
# %%
order_reviews_df = pd.read_csv(
"https://media.githubusercontent.com/media/fxrdhan/Data-Analysis-Project/refs/heads/main/e-commerce_public_dataset/order_reviews_dataset.csv"
)
order_reviews_df.head()
# %% [markdown]
# **Insight:**\
# Dataset `order_reviews_df` berisi informasi mengenai ulasan pelanggan terhadap pesanan yang telah mereka terima.\
# Informasi yang tertera diantaranya:
#
# 1. `review_id`: ID unik untuk setiap ulasan.
# 2. `order_id`: ID unik dari pesanan.
# 3. `review_score`: Skor ulasan yang diberikan oleh pelanggan, pada skala 1-5.
# 4. `review_comment_title` & `review_comment_message`: Komentar pelanggan.
# 5. `review_creation_date` $ `review_answer_timestamp`: Waktu ketika ulasan dibuat dan dijawab.
#
# %% [markdown]
# #### Data Tabel `order_payments`
#
# %%
order_payments_df = pd.read_csv(
"https://media.githubusercontent.com/media/fxrdhan/Data-Analysis-Project/refs/heads/main/e-commerce_public_dataset/order_payments_dataset.csv"
)
order_payments_df.head()
# %% [markdown]
# **Insight:**\
# Dataset `order_payments` ini berisi informasi mengenai pembayaran yang dilakukan pelanggan untuk pesanan yang mereka buat.\
# Informasi yang tertera diantaranya:
#
# 1. `order_id`: ID unik untuk setiap pesanan.
# 2. `payment_sequential`: Urutan pembayaran untuk setiap pesanan.
# 3. `payment_type`: Jenis pembayaran yang digunakan oleh pelanggan.
# 4. `payment_installments`: Jumlah cicilan yang diambil oleh pelanggan untuk membayar pesanan.
# 5. `payment_value`: Nilai total dari setiap pembayaran.
#
# %% [markdown]
# #### Data Tabel `order_items_df`
#
# %%
order_items_df = pd.read_csv(
"https://media.githubusercontent.com/media/fxrdhan/Data-Analysis-Project/refs/heads/main/e-commerce_public_dataset/order_items_dataset.csv"
)
order_items_df.head()
# %% [markdown]
# **Insight:**\
# Dataset `order_items_df` berisi informasi mengenai item yang dipesan dalam setiap pesanan.\
# Informasi yang tertera diantaranya:
#
# 1. `order_id`: ID unik untuk setiap pesanan.
# 2. `order_item_id`: ID untuk setiap item pesanan dalam pesanan yang sama.
# 3. `product_id`: ID produk yang dipesan.
# 4. `seller_id`: ID unik penjual.
# 5. `shipping_limit_date`: Batas waktu pengiriman item oleh penjual.
# 6. `price`: Harga jual produk yang dipesan.
# 7. `freight_value`: Biaya pengiriman item.
#
# %% [markdown]
# #### Data Tabel `geolocation_df`
#
# %%
geolocation_df = pd.read_csv(
"https://media.githubusercontent.com/media/fxrdhan/Data-Analysis-Project/refs/heads/main/e-commerce_public_dataset/geolocation_dataset.csv"
)
geolocation_df.head()
# %% [markdown]
# **Insight:**\
# Dataset `geolocation_df` berisi informasi geolokasi.\
# Informasi yang tertera diantaranya:
#
# 1. `geolocation_zip_code_prefix`: Kode pos.
# 2. `geolocation_lat`: Koordinat geografis lintang.
# 3. `geolocation_lng`: Koordinat geografis bujur.
# 4. `geolocation_city`: Nama kota.
# 5. `geolocation_state`: Nama negara bagian.
#
# %% [markdown]
# #### Data Tabel `customers_df`
#
# %%
customers_df = pd.read_csv(
"https://media.githubusercontent.com/media/fxrdhan/Data-Analysis-Project/refs/heads/main/e-commerce_public_dataset/customers_dataset.csv"
)
customers_df.head()
# %% [markdown]
# **Insight:**\
# Dataset `customers_df` berisi informasi mengenai pelanggan yang melakukan pemesanan.\
# Informasi yang tertera diantaranya:
#
# 1. `customer_id`: ID pelanggan untuk setiap pesanan.
# 2. `customer_unique_id`: ID unik pelanggan.
# 3. `customer_zip_code_prefix`: Kode pos pelanggan.
# 4. `customer_city`: Nama kota pelanggan.
# 5. `customer_state`: Nama negara bagian pelanggan.
#
# %% [markdown]
# #### Data Tabel `sellers_df`
#
# %%
sellers_df = pd.read_csv(
"https://media.githubusercontent.com/media/fxrdhan/Data-Analysis-Project/refs/heads/main/e-commerce_public_dataset/sellers_dataset.csv"
)
sellers_df.head()
# %% [markdown]
# **Insight:**\
# Dataset `sellers_df` berisi informasi penjual\
# Informasi yang tertera diantaranya:
#
# 1. `seller_id`: ID penjual.
# 2. `seller_zip_code_prefix`: Kode pos penjual.
# 3. `seller_city`: Nama kota penjual.
# 4. `seller_state`: Nama negara bagian penjual.
#
# %% [markdown]
# #### Data Tabel `orders_df`
#
# %%
orders_df = pd.read_csv(
"https://media.githubusercontent.com/media/fxrdhan/Data-Analysis-Project/refs/heads/main/e-commerce_public_dataset/orders_dataset.csv"
)
orders_df.head()
# %% [markdown]
# **Insight:**\
# Dataset `orders_df` berisi informasi mengenai pesanan yang dibuat oleh pelanggan.\
# Informasi yang tertera diantaranya:
#
# 1. `order_id`: ID unik untuk setiap pesanan.
# 2. `customer_id`: ID pelanggan yang terkait dengan pesanan.
# 3. `order_status`: Status pesanan yang menunjukkan tahapan pesanan seperti delivered, shipped, canceled, dll.
# 4. `order_purchase_timestamp`: Tanggal dan waktu pesanan dibuat.
# 5. `order_approved_at`: Waktu persetujuan pesanan.
# 6. `order_delivered_carrier_date`: Tanggal pesanan dikirim ke pelanggan oleh kurir.
# 7. `order_delivered_customer_date`: Tanggal pesanan diterima oleh pelanggan.
# 8. `order_estimated_delivery_date`: Estimasi tanggal pengiriman pesanan.
#
# %% [markdown]
# ### Assessing Data
#
# %% [markdown]
# #### Menilai Tabel `products_df`
#
# %%
products_df.info()
# %%
print("\nMissing values in Products dataset:")
products_df.isna().sum()
# %%
print("Duplicates in Products dataset:", products_df.duplicated().sum())
# %%
products_df["product_weight_g"].describe().round(2)
# %% [markdown]
# **Insight:**\
# Tidak ada data duplikat.\
# Terdapat beberapa kolom memiliki nilai yang hilang.\
# Rentang nilai `product_weight_g` cukup besar, mulai dari **0.00** hingga **40425** gram, yang menunjukkan adanya anomali pada nilai minimum. Nilai **0.00** pada berat produk tampak tidak logis.
#
# %% [markdown]
# #### Menilai Tabel `product_category_translation_df`
#
# %%
product_category_translation_df.info()
# %%
print("\nMissing values in Product Category Translation dataset:")
product_category_translation_df.isna().sum()
# %%
print(
"Duplicates in Product Category Translation dataset:",
product_category_translation_df.duplicated().sum(),
)
# %% [markdown]
# **Insight:**\
# Setiap kategori produk dalam bahasa Portugis dan terjemahan bahasa Inggris, sesuai dengan jumlah total entri **(71)**.\
# Tidak memiliki nilai yang hilang atau duplikat.
#
# %% [markdown]
# #### Menilai Tabel `order_reviews_df`
#
# %%
order_reviews_df.info()
# %%
print("\nMissing values in Order Reviews dataset:")
order_reviews_df.isna().sum()
# %%
print("Duplicates in Order Reviews dataset:", order_reviews_df.duplicated().sum())
# %% [markdown]
# **Insight:**\
# Anomali pada kolom `review_creation_date` & `review_answer_timestamp` yang bertipe data _object_ (teks).
# Terdapat banyak nilai yang hilang pada entri `review_comment_title` dan `review_comment_message`.\
# Tidak ada baris yang duplikat.\
#
# %% [markdown]
# #### Menilai Tabel `order_payments_df`
#
# %%
order_payments_df.info()
# %%
print("\nMissing values in Order Payments dataset:")
order_payments_df.isna().sum()
# %%
print("Duplicates in Order Payments dataset:", order_payments_df.duplicated().sum())
# %%
order_payments_df.describe()
# %% [markdown]
# **Insight:**\
# Tidak ada _missing values_.\
# Tidak ada data duplikat.\
# Pada kolom `payment_installments` dengan minimum value **0.00**, yang mungkin menunjukkan pembayaran tanpa cicilan.\
# Pada kolom `payment_value`, nilai minimum adalah **0.00**, yang mungkin barang tersebut digratiskan atau sedang promo.
#
# %% [markdown]
# #### Menilai Tabel `order_items_df`
#
# %%
order_items_df.info()
# %%
print("\nMissing values in Order Items dataset:")
order_items_df.isna().sum()
# %%
print("Duplicates in Order Items dataset:", order_items_df.duplicated().sum())
# %% [markdown]
# **Insight:**\
# Anomali pada kolom `shipping_limit_date` yang bertipe data _object_ (teks).\
# Tidak ada _missing values_.\
# Tidak ada baris yang duplikat.
#
# %% [markdown]
# #### Menilai Tabel `geolocation_df`
#
# %%
geolocation_df.info()
# %%
print("\nMissing values in Geolocation dataset:")
geolocation_df.isna().sum()
# %%
print("Duplicates in Geolocation dataset:", geolocation_df.duplicated().sum())
# %% [markdown]
# **Insight:**\
# Tidak ada _missing values_.\
# Terdapat **261831** baris duplikat, sekitar **26%** dari keseluruhan data.
#
# %% [markdown]
# #### Menilai Tabel `customers_df`
#
# %%
customers_df.info()
# %%
print("\nMissing values in Customers dataset:")
customers_df.isna().sum()
# %%
print("Duplicates in Customers dataset:", customers_df.duplicated().sum())
# %% [markdown]
# **Insight:**\
# Tidak ada anomali tipe data.\
# Tidak ada _missing values_.\
# Tidak ada baris yang duplikat.
#
# %% [markdown]
# #### Menilai Tabel `sellers_df`
#
# %%
sellers_df.info()
# %%
print("\nMissing values in Sellers dataset:")
sellers_df.isna().sum()
# %%
print("Duplicates in Sellers dataset:", sellers_df.duplicated().sum())
# %% [markdown]
# **Insight:**\
# Tidak ada anomali tipe data.\
# Tidak ada _missing values._\
# Tidak ada bairs yang duplikat.
#
# %% [markdown]
# #### Menilai Tabel `orders_df`
#
# %%
orders_df.info()
# %%
print("Duplicates in Orders dataset:", orders_df.duplicated().sum())
# %%
print("\nMissing values in Orders dataset:")
orders_df.isna().sum()
# %% [markdown]
# **Insight:**\
# Anomali pada kolom `order_purchase_timestamp`, `order_approved_at`, `order_delivered_carrier_date`, `order_delivered_customer_date`, dan `order_estimated_delivery_date` dengan tipe data _object_ (teks).\
# Tidak ada baris yang duplikat.\
# Nilai-nilai yang hilang pada dataset berkaitan dengan tahapan proses pesanan, yang bisa disebabkan oleh pesanan yang belum selesai atau pembatalan.\
#
# %% [markdown]
# ### Cleaning Data
#
# %% [markdown]
# #### Membersihkan Tabel `products_df`
#
# %%
products_df.info()
# %% [markdown]
# **FIXING:** Missing Values
#
# %%
print("\nMissing values in Products dataset:")
products_df.isna().sum()
# %%
missing_values = products_df[products_df.isna().any(axis=1)]
missing_values.head()
# %%
products_df.loc[:, "product_category_name"] = products_df[
"product_category_name"
].fillna("unknown")
# %%
unknown_count = products_df[products_df["product_category_name"] == "unknown"].shape[0]
print(
f"Number of rows with 'unknown' entries in 'product_category_name': {unknown_count}"
)
# %%
print("Product weight statistics:\n")
products_df["product_weight_g"].describe().round(2)
# %%
products_df.loc[
products_df["product_weight_g"] == 0,
["product_id", "product_category_name", "product_weight_g"],
]
# %%
cama_mesa_banho_df = products_df[
products_df["product_category_name"] == "cama_mesa_banho"
]
products_df.loc[
(products_df["product_category_name"] == "cama_mesa_banho")
& (products_df["product_weight_g"] == 0),
"product_weight_g",
] = cama_mesa_banho_df["product_weight_g"].median()
# %%
print("Product weight statistics:\n")
products_df["product_weight_g"].describe().round(2)
# %%
products_df["product_name_lenght"] = products_df["product_name_lenght"].fillna(
products_df["product_name_lenght"].mean().round(2)
)
products_df["product_description_lenght"] = products_df[
"product_description_lenght"
].fillna(products_df["product_description_lenght"].mean().round(2))
products_df["product_photos_qty"] = products_df["product_photos_qty"].fillna(
products_df["product_photos_qty"].mean().round(2)
)
# %%
print("\nMissing values in Products dataset:")
products_df.isna().sum()
# %%
missing_rows = products_df[
products_df[
[
"product_weight_g",
"product_name_lenght",
"product_height_cm",
"product_width_cm",
]
]
.isna()
.any(axis=1)
]
missing_rows
# %%
columns_to_fill = [
"product_weight_g",
"product_length_cm",
"product_height_cm",
"product_width_cm",
]
categories = ["bebes", "unknown"]
for category in categories:
for column in columns_to_fill:
products_df.loc[
products_df["product_category_name"] == category, column
] = products_df[products_df["product_category_name"] == category][
column
].fillna(
products_df[products_df["product_category_name"] == category][column]
.mean()
.round(2)
)
# %%
products_df.info()
# %% [markdown]
# **Insigth:**\
# _Missing values_ sebanyak **610** pada `product_category_name` berhasil diisi dengan nama kategori produk 'unknown' karena hilangnya informasi pada dataset.\
# _Missing values_ sebanyak **610** pada [`product_name_length`, `product_description_length`, `product_photos_qty`] berhasil diisi dengan nilai _mean_ dari masing-masing kolom mereka.
#
# Nilai _NaN_ di kolom `product_weight_g`, `product_length_cm`, `product_height_cm`, dan `product_width_cm` untuk kategori 'bebes' dan 'unknown' telah diisi menggunakan rata-rata (mean) masing-masing kolom untuk setiap kategori. Pendekatan ini memastikan bahwa setiap kategori produk memiliki nilai yang lebih representatif dibanding menggunakan satu nilai median atau mean secara keseluruhan.
#
# Rentang berat produk `product_weight_g` yang dimulai dari **0.00** hingga **40425** gram, menunjukkan adanya anomali dengan adanya berat produk sebesar **0.00** gram yang telah digantikan dengan nilai _median_.
#
# %% [markdown]
# #### Membersihkan Tabel `order_reviews.df`
#
# %%
order_reviews_df.info()
# %% [markdown]
# **FIXING:** Data Types
#
# %%
order_reviews_df[["review_creation_date", "review_answer_timestamp"]].dtypes
# %%
order_reviews_df["review_creation_date"] = pd.to_datetime(
order_reviews_df["review_creation_date"]
)
order_reviews_df["review_answer_timestamp"] = pd.to_datetime(
order_reviews_df["review_answer_timestamp"]
)
order_reviews_df[["review_creation_date", "review_answer_timestamp"]].dtypes
# %% [markdown]
# **Insight:**\
# Kolom `review_creation_date` dan `review_answer_timestamp` telah dikonversi menjadi _datetime_.
#
# %% [markdown]
# **FIXING:** Missing Values
#
# %%
order_reviews_df.isna().sum()
# %%
order_reviews_df.loc[:, ["review_comment_title", "review_comment_message"]] = (
order_reviews_df.loc[:, ["review_comment_title", "review_comment_message"]].fillna(
"empty"
)
)
empty_samples = order_reviews_df[
(order_reviews_df["review_comment_title"] == "empty")
| (order_reviews_df["review_comment_message"] == "empty")
]
empty_samples.sample(5)
# %%
empty_samples_title = order_reviews_df[
order_reviews_df["review_comment_title"] == "empty"
]
empty_samples_message = order_reviews_df[
order_reviews_df["review_comment_message"] == "empty"
]
print(
f"'empty' values in review_comment_title or review_comment_message: {empty_samples_title.shape[0]}"
)
print(f"'empty' values in review_comment_message: {empty_samples_message.shape[0]}")
# %%
order_reviews_df.isna().sum()
# %% [markdown]
# **Insight:**\
# _Missing values_ pada kolom `review_comment_title` dan `review_comment_message` telah diisi dengan 'empty' untuk mengisi kekosongan data.
#
# %% [markdown]
# #### Membersihkan Tabel `order_items_df`
#
# %% [markdown]
# **FIXING:** Data Types
#
# %%
print(f"Data type [shipping_limit_date]: {order_items_df['shipping_limit_date'].dtype}")
# %%
order_items_df["shipping_limit_date"] = pd.to_datetime(
order_items_df["shipping_limit_date"]
)
# %%
order_items_df.info()
# %% [markdown]
# **Insight:**\
# Kolom `shipping_limit_date` telah dikonversi ke tipe data _datetime_.\
# Kolom `freight_value` tetap menyertakan nilai **0.00** karena munkin saja merepresentasikan _free shipping_.
#
# %% [markdown]
# #### Membersihkan Tabel `geolocation_df`
#
# %%
print("Duplicates in Geolocation dataset:", geolocation_df.duplicated().sum())
# %% [markdown]
# **FIXING:** Duplicates
#
# %%
geolocation_df = geolocation_df.drop_duplicates()
remaining_duplicates_count = geolocation_df.duplicated().sum()
# %%
print("Remaining duplicates in Geolocation dataset:", remaining_duplicates_count)
# %%
geolocation_df.info()
# %% [markdown]
# **Insight:**\
# Sebanyak **261831** baris duplikat telah dihapus.
#
# %% [markdown]
# #### Membersihkan Tabel `orders_df`
#
# %% [markdown]
# **FIXING:** Data Types
#
# %%
columns = [
"order_purchase_timestamp",
"order_approved_at",
"order_delivered_carrier_date",
"order_delivered_customer_date",
"order_estimated_delivery_date",
]
for col in columns:
print(f"{col:<35} {orders_df[col].dtypes}")
# %%
for col in columns:
orders_df[col] = pd.to_datetime(orders_df[col], errors="coerce")
print(f"{col:<35} {orders_df[col].dtypes}")
# %% [markdown]
# **Insight:**\
# Kolom `order_purchase_timestamp`, `order_approved_at`, `order_delivered_carrier_date`, `order_delivered_customer_date`, dan `order_estimated_delivery_date` telah berhasil dikonversi menjadi tipe data _datetime_.
#
# %% [markdown]
# **FIXING:** Missing Values
#
# %%
print("\nMissing values in Orders dataset:")
orders_df.isna().sum()
# %%
missing_approved_at = orders_df[orders_df["order_approved_at"].isna()]
missing_approved_delivered = missing_approved_at[
missing_approved_at["order_status"] == "delivered"
]
print("\nSample rows with missing 'order_approved_at' and status 'delivered':")
missing_approved_delivered.sample(3)
# %%
orders_df["approval_time_diff"] = (
orders_df["order_approved_at"] - orders_df["order_purchase_timestamp"]
).dt.total_seconds() / 3600
orders_df["approval_time_diff"] = orders_df["approval_time_diff"].round(2)
average_approval_time = orders_df["approval_time_diff"].mean()
orders_df["order_approved_at"] = orders_df["order_approved_at"].fillna(
orders_df["order_purchase_timestamp"]
+ pd.to_timedelta(average_approval_time, unit="h")
)
orders_df["order_approved_at"] = orders_df["order_approved_at"].dt.round("s")
orders_df.sample(3)
# %%
print(
"NaN values in 'approval_time_diff':", orders_df["approval_time_diff"].isna().sum()
)
# %%
average_approval_time = orders_df["approval_time_diff"].mean()
orders_df["approval_time_diff"] = orders_df["approval_time_diff"].fillna(
average_approval_time
)
orders_df["approval_time_diff"] = orders_df["approval_time_diff"].round(2)
# %%
print(
"NaN values in 'approval_time_diff':", orders_df["approval_time_diff"].isna().sum()
)
# %%
# orders_df = orders_df.dropna(subset=["order_delivered_carrier_date"])
# orders_df = orders_df.dropna(subset=["order_delivered_customer_date"])
# %%
print("\nMissing values in Orders dataset:")
orders_df.isna().sum()
# %%
orders_df.info()
# %% [markdown]
# **Insight:**\
# Terdapat beberapa `order_status` 'delivered' yang mempunyai nilai kosong pada `order_approved_at`.\
# Kolom `order_approved_at` yang memiliki nilai kosong telah diisi dengan menghitung rata-rata waktu persetujuan dari pesanan yang sudah memiliki nilai di `order_approved_at` (selisih waktu antara `order_purchase_timestamp` dan `order_approved_at`).\
#
# _NaT_ pada kolom `order_delivered_carrier_date` dan `order_delivered_customer_date` tetap, karena disesuaikan dengan keadaan aktual dimana pesanan belum memasuki status pengiriman.
#
# %% [markdown]
# ## Exploratory Data Analysis (EDA)
#
# %% [markdown]
# ### Eksplorasi Data `orders_df`
#
# %%
orders_df.head(3)
# %%
orders_df.info()
print(f"\n(rows, collumns): \t\t{orders_df.shape}")
print(f"nunique of order_id: \t\t{orders_df['order_id'].nunique()}")
print(f"nunique of customer_id: \t{orders_df['customer_id'].nunique()}")
print(f"nunique of order_status: \t{orders_df['order_status'].nunique()}")
# %%
status_counts = orders_df["order_status"].value_counts()
total_orders = status_counts.sum()
status_percentages = (status_counts / total_orders) * 100
pd.DataFrame(
{
"Count": status_counts.values,
"Percentage": status_percentages.round(2).map("{:.2f}%".format),
}
)
# %%
stats = orders_df["approval_time_diff"].describe().round(2)
pd.DataFrame({"Statistic": stats.index, "Value": stats.values})
# %%
delivered_status_df = orders_df[orders_df["order_status"] == "delivered"].sort_values(
"approval_time_diff", ascending=False
)
delivered_status_df[["order_id", "order_status", "approval_time_diff"]]
# %%
canceled_status_df = orders_df[orders_df["order_status"] == "canceled"].sort_values(
"approval_time_diff", ascending=False
)
canceled_status_df[["order_id", "order_status", "approval_time_diff"]]
# %% [markdown]
# **Insight:**
#
# - Sebanyak 97% pesanan memiliki status "delivered", menunjukkan bahwa sistem pengiriman berjalan dengan baik dan memiliki tingkat keberhasilan yang tinggi.
# - Persentase pembatalan hanya sebesar 0,63%, yang menunjukkan bahwa jumlah pesanan yang dibatalkan sangat rendah dibandingkan total pesanan.
# - Rata-rata waktu persetujuan adalah 10,42 jam, dengan variasi yang cukup besar.
#
# %% [markdown]
# ### Eksplorasi Data `order_reviews_df`
#
# %%
order_reviews_df.sample(5).T
# %%
order_reviews_df.describe(include="all").T
# %%
review_counts = order_reviews_df["review_score"].value_counts().sort_index()
total_reviews = review_counts.sum()
pd.DataFrame(
{
"Score Count": review_counts.values,
"Percentage": (review_counts / total_reviews * 100)
.round(2)
.map("{:.2f}%".format),
}
)
# %% [markdown]
# **Insight:**\
# Berdasarkan distribusi Review Score pada e-commerce, mayoritas ulasan menunjukkan kepuasan tinggi dengan skor **5** yang memiliki kontribusi sebesar **57.78%** dari total ulasan. Diikuti oleh skor **4** yang memberikan kontribusi sebesar **19.29%**.
#
# %% [markdown]
# ### Merge Data `orders_df` dan `order_reviews_df`
#
# %%
order_orders_reviews_df = pd.merge(
orders_df,
order_reviews_df,
on="order_id",
how="inner",
)
order_orders_reviews_df["review_score"] = order_orders_reviews_df[
"review_score"
].astype("Int64")
# %%
order_orders_reviews_df.sample(5).T
# %%
canceled_status_df = order_orders_reviews_df[
(order_orders_reviews_df["order_status"] == "canceled")
]
canceled_status_df.head().T
# %%
canceled_reviews_df = order_orders_reviews_df[
(order_orders_reviews_df["order_status"] == "canceled")
& (order_orders_reviews_df["review_comment_message"] != "empty")
]
colls_df = canceled_reviews_df[
[
"order_id",
"order_status",
"customer_id",
"review_id",
"review_score",
"review_comment_message",
]
].sample(5)
colls_df.T
# %%
canceled_reviews_translated_df = canceled_reviews_df.copy()
canceled_reviews_translated_df[
"review_comment_message"
] = canceled_reviews_translated_df["review_comment_message"].apply(
lambda x: (Translator(source="pt", target="en").translate(x) if pd.notna(x) else "")
)
translated_df = canceled_reviews_translated_df[
[
"order_id",
"order_status",
"customer_id",
"review_id",
"review_score",
"review_comment_message",
]
]
pd.set_option("display.max_colwidth", None)
translated_df.head().T
# %% [markdown]
# ### Eksplorasi Data `order_items_df`
#
# %%
print(order_items_df.info())
print(f"\nnunique of order_id: \t\t{order_items_df['order_id'].nunique()}")
print(f"nunique of product_id: \t\t{order_items_df['product_id'].nunique()}")
print(f"nunique of seller_id: \t\t{order_items_df['seller_id'].nunique()}")
# %%
merged_items_reviews_df = pd.merge(
order_reviews_df, order_items_df, on="order_id", how="left"
)
selected_colls = merged_items_reviews_df[
[
"order_id",
"review_id",
"review_score",
"order_item_id",
"seller_id",
"product_id",
]
]
multi_item_orders = selected_colls.groupby("order_id").filter(
lambda x: x["product_id"].nunique() > 1
)
multi_item_orders.head(6)
# %% [markdown]
# **Insight:**
#
# 1. `multi_item_order`:
# - `order_id` <span style="color:orange">b18dcdf73be66366873cd26c5724d1dc</span> memiliki beberapa item yang berbeda (`order_item_id` 1, 2, 3, dan 4). Semua item ini terkait dengan satu ulasan (berdasarkan `review_id`), dan pelanggan memberikan skor **1** untuk keseluruhan pesanan.
# - `order_id` <span style="color:orange">d7bd0e4afdf94846eb73642b4e3e75c3</span> juga memuat lebih dari satu item, dan pelanggan memberikan skor **3**.
# 2. Ini memberikan gambaran jelas bahwa dalam beberapa kasus, satu `order_id` memang dapat berisi beberapa produk (berdasarkan `product_id`). Namun, ulasan diberikan satu kali untuk pesanan tersebut (berdasarkan `order_id` dan `review_id`), meskipun pesanan tersebut terdiri dari beberapa produk (berdasarkan `order_item_id`).
#
# %% [markdown]
# ### Eksplorasi Data `products_df`