TA/web_JMW/docs/append_code_usage_explanati...

306 lines
12 KiB
Python

from pathlib import Path
from zipfile import ZIP_DEFLATED, ZipFile
import tempfile
import xml.etree.ElementTree as ET
SOURCE_DOC = Path("docs/Penjelasan_Rinci_KMeans_Rekomendasi_JMW_Gabungan.docx")
OUT_DOC = Path("docs/Penjelasan_Rinci_KMeans_Rekomendasi_JMW_Gabungan_Update.docx")
WORD_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
ET.register_namespace("w", WORD_NS)
def qn(name):
return f"{{{WORD_NS}}}{name}"
def paragraph(text="", style=None):
p = ET.Element(qn("p"))
if style:
p_pr = ET.SubElement(p, qn("pPr"))
p_style = ET.SubElement(p_pr, qn("pStyle"))
p_style.set(qn("val"), style)
run = ET.SubElement(p, qn("r"))
t = ET.SubElement(run, qn("t"))
t.set("{http://www.w3.org/XML/1998/namespace}space", "preserve")
t.text = text
return p
def code_paragraph(text):
p = ET.Element(qn("p"))
p_pr = ET.SubElement(p, qn("pPr"))
p_style = ET.SubElement(p_pr, qn("pStyle"))
p_style.set(qn("val"), "Code")
run = ET.SubElement(p, qn("r"))
t = ET.SubElement(run, qn("t"))
t.set("{http://www.w3.org/XML/1998/namespace}space", "preserve")
t.text = text
return p
def page_break():
p = ET.Element(qn("p"))
r = ET.SubElement(p, qn("r"))
br = ET.SubElement(r, qn("br"))
br.set(qn("type"), "page")
return p
def code_block(text):
return [code_paragraph(line) for line in text.strip("\n").splitlines()]
def new_section():
items = []
items.append(page_break())
items.append(paragraph("17. Penjelasan Kode Clustering dan Kegunaannya dalam Sistem", "Heading1"))
items.append(paragraph(
"Bagian ini menjelaskan fungsi setiap blok kode clustering K-Means dan hubungannya dengan fitur rekomendasi "
"mobil berdasarkan budget pada sistem JMW Showroom. Kode clustering digunakan untuk membentuk kelompok mobil "
"berdasarkan kemiripan harga, tahun, dan kapasitas mesin."
))
items.append(paragraph("17.1 Import Library", "Heading2"))
items.extend(code_block("""
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
"""))
items.append(paragraph(
"Kode ini digunakan untuk memanggil library yang diperlukan. pandas dipakai untuk membaca dan mengolah dataset. "
"StandardScaler digunakan untuk menstandarkan nilai atribut agar skala harga, tahun, dan mesin_cc menjadi "
"seimbang. KMeans digunakan untuk melakukan proses clustering, sedangkan silhouette_score digunakan untuk "
"menilai kualitas pembentukan cluster."
))
items.append(paragraph(
"Kegunaannya dalam sistem adalah menyiapkan alat utama untuk mengolah data mobil sebelum data tersebut dipakai "
"sebagai dasar rekomendasi."
))
items.append(paragraph("17.2 Membaca Dataset", "Heading2"))
items.extend(code_block("""
df = pd.read_csv("dataset_final.csv")
"""))
items.append(paragraph(
"Kode ini membaca file dataset_final.csv yang berisi data mobil. Dataset tersebut memuat informasi seperti "
"merk, model, harga, tahun, mesin_cc, transmisi, bahan bakar, dan atribut lainnya."
))
items.append(paragraph(
"Dalam sistem, dataset ini menjadi sumber data utama untuk membentuk cluster. Jika data mobil berubah atau "
"ditambah, proses clustering dapat dijalankan kembali agar hasil rekomendasi mengikuti data terbaru."
))
items.append(paragraph("17.3 Menghapus Cluster Lama", "Heading2"))
items.extend(code_block("""
if "cluster" in df.columns:
df = df.drop(columns=["cluster"])
"""))
items.append(paragraph(
"Kode ini mengecek apakah dataset sudah memiliki kolom cluster. Jika ada, kolom tersebut dihapus terlebih "
"dahulu. Tujuannya agar proses clustering tidak memakai hasil lama, tetapi menghitung ulang cluster dari awal."
))
items.append(paragraph(
"Kegunaannya dalam sistem adalah menjaga agar hasil cluster selalu sesuai dengan data dan proses perhitungan "
"terbaru, bukan hasil clustering sebelumnya."
))
items.append(paragraph("17.4 Menyamakan Nama Kolom Harga", "Heading2"))
items.extend(code_block("""
if "Harga" in df.columns:
df = df.rename(columns={"Harga": "harga"})
"""))
items.append(paragraph(
"Kode ini menyamakan nama kolom Harga menjadi harga. Penyamaan nama kolom penting karena kode clustering "
"mengambil atribut dengan nama harga, tahun, dan mesin_cc."
))
items.append(paragraph(
"Dalam sistem, hal ini membantu mencegah error ketika dataset menggunakan nama kolom dengan huruf besar, "
"misalnya Harga, sedangkan kode membaca kolom harga."
))
items.append(paragraph("17.5 Memilih Tiga Atribut Utama", "Heading2"))
items.extend(code_block("""
fitur = df[
[
"harga",
"tahun",
"mesin_cc"
]
]
"""))
items.append(paragraph(
"Kode ini memilih tiga atribut yang digunakan untuk clustering, yaitu harga, tahun, dan mesin_cc. Ketiga atribut "
"tersebut dipakai karena berhubungan langsung dengan rekomendasi mobil bekas. Harga menentukan kesesuaian "
"dengan budget, tahun menunjukkan usia kendaraan, dan mesin_cc menunjukkan kapasitas mesin."
))
items.append(paragraph(
"Kegunaannya dalam sistem adalah menentukan dasar pengelompokan mobil. Mobil dengan harga, tahun, dan mesin "
"yang mirip akan cenderung masuk ke cluster yang sama."
))
items.append(paragraph("17.6 Standarisasi Data", "Heading2"))
items.extend(code_block("""
scaler = StandardScaler()
fitur_scaled = scaler.fit_transform(fitur)
"""))
items.append(paragraph(
"Kode ini melakukan standarisasi data. Standarisasi diperlukan karena nilai harga sangat besar dibandingkan "
"tahun dan mesin_cc. Jika tidak distandarisasi, perhitungan jarak pada K-Means akan terlalu dipengaruhi oleh "
"harga, sehingga atribut tahun dan mesin_cc menjadi kurang berpengaruh."
))
items.append(paragraph(
"Dalam sistem, standarisasi membuat proses clustering lebih adil karena semua atribut berada pada skala yang "
"seimbang sebelum dihitung jaraknya."
))
items.append(paragraph("17.7 Mencari Jumlah Cluster Terbaik", "Heading2"))
items.extend(code_block("""
for k in range(2, 7):
kmeans = KMeans(
n_clusters=k,
random_state=42,
n_init=10
)
labels = kmeans.fit_predict(fitur_scaled)
score = silhouette_score(fitur_scaled, labels)
print(f"Jumlah Cluster: {k}, Silhouette Score: {score}")
"""))
items.append(paragraph(
"Kode ini mencoba beberapa jumlah cluster, mulai dari 2 sampai 6. Setiap nilai k diuji dengan K-Means, lalu "
"hasilnya dinilai menggunakan silhouette_score. Nilai silhouette digunakan untuk melihat seberapa baik data "
"terpisah ke dalam cluster."
))
items.append(paragraph(
"Kegunaannya dalam sistem adalah membantu menentukan jumlah cluster yang paling sesuai. Dengan cara ini, jumlah "
"cluster tidak dipilih secara asal, tetapi berdasarkan hasil evaluasi."
))
items.append(paragraph("17.8 Membuat Model K-Means Akhir", "Heading2"))
items.extend(code_block("""
kmeans = KMeans(
n_clusters=4,
random_state=42,
n_init=10
)
"""))
items.append(paragraph(
"Kode ini membuat model K-Means akhir dengan jumlah cluster sebanyak 4. Angka 4 disesuaikan dengan konfigurasi "
"pada sistem rekomendasi yang mengirim parameter jumlah_cluster = 4 ke Flask API."
))
items.append(paragraph(
"Dalam sistem, model ini berfungsi untuk membagi data mobil ke dalam empat kelompok. Setiap kelompok berisi "
"mobil yang memiliki karakteristik harga, tahun, dan mesin_cc yang relatif mirip."
))
items.append(paragraph("17.9 Menambahkan Hasil Cluster ke Dataset", "Heading2"))
items.extend(code_block("""
df["cluster"] = kmeans.fit_predict(fitur_scaled)
"""))
items.append(paragraph(
"Kode ini menjalankan K-Means pada data yang sudah distandarisasi, lalu menyimpan hasil cluster ke kolom baru "
"bernama cluster. Setiap mobil akan mendapatkan label cluster, misalnya 0, 1, 2, atau 3."
))
items.append(paragraph(
"Kegunaannya dalam sistem adalah memberikan identitas kelompok pada setiap mobil. Label cluster ini dapat "
"dipakai untuk memilih kandidat mobil yang paling sesuai dengan budget pengguna."
))
items.append(paragraph("17.10 Menampilkan dan Menyimpan Hasil", "Heading2"))
items.extend(code_block("""
print(
df[
[
"merk",
"model",
"harga",
"tahun",
"mesin_cc",
"cluster"
]
].head(20)
)
df.to_csv("dataset_final_clustered.csv", index=False)
"""))
items.append(paragraph(
"Kode ini menampilkan sebagian hasil clustering agar peneliti dapat melihat apakah setiap mobil sudah memiliki "
"label cluster. Setelah itu, dataset disimpan ke file baru bernama dataset_final_clustered.csv."
))
items.append(paragraph(
"Dalam sistem, file hasil clustering dapat digunakan sebagai dataset yang sudah siap dipakai untuk proses "
"rekomendasi. Data tersebut berisi informasi mobil beserta cluster-nya."
))
items.append(paragraph("17.11 Hubungan Kode dengan Fitur Rekomendasi Budget", "Heading2"))
items.append(paragraph(
"Secara keseluruhan, kode clustering ini berfungsi untuk mengelompokkan mobil sebelum proses rekomendasi "
"dilakukan. Ketika pengguna memasukkan budget, sistem dapat mencari kelompok mobil yang karakteristiknya paling "
"mendekati budget tersebut. Setelah cluster yang sesuai ditemukan, sistem menyaring mobil yang harganya tidak "
"melebihi budget pengguna dan mengurutkan hasil rekomendasi."
))
items.append(paragraph(
"Dengan demikian, K-Means tidak hanya menampilkan mobil berdasarkan harga terdekat, tetapi membantu sistem "
"mempertimbangkan kemiripan karakteristik kendaraan berdasarkan harga, tahun, dan kapasitas mesin."
))
items.append(paragraph("Kalimat Ringkas untuk Laporan", "Heading2"))
items.append(paragraph(
"Kode clustering digunakan untuk mengelompokkan data mobil berdasarkan atribut harga, tahun, dan mesin_cc. "
"Sebelum dilakukan clustering, data distandarisasi agar setiap atribut memiliki skala yang seimbang. Setelah "
"model K-Means dijalankan, setiap mobil memperoleh label cluster. Label cluster tersebut digunakan sistem "
"sebagai dasar dalam memilih kandidat rekomendasi mobil yang sesuai dengan budget pengguna."
))
return items
def append_section():
OUT_DOC.parent.mkdir(parents=True, exist_ok=True)
with tempfile.TemporaryDirectory() as tmp:
tmp_dir = Path(tmp)
with ZipFile(SOURCE_DOC, "r") as archive:
archive.extractall(tmp_dir)
document_path = tmp_dir / "word" / "document.xml"
root = ET.parse(document_path).getroot()
body = root.find(qn("body"))
sect_pr = None
for child in list(body):
if child.tag == qn("sectPr"):
sect_pr = child
body.remove(child)
break
for item in new_section():
body.append(item)
if sect_pr is not None:
body.append(sect_pr)
ET.ElementTree(root).write(document_path, encoding="utf-8", xml_declaration=True)
if OUT_DOC.exists():
OUT_DOC.unlink()
with ZipFile(OUT_DOC, "w", ZIP_DEFLATED) as archive:
for path in tmp_dir.rglob("*"):
if path.is_file():
archive.write(path, path.relative_to(tmp_dir).as_posix())
print(OUT_DOC.resolve())
if __name__ == "__main__":
append_section()