TA/web_JMW/docs/append_initial_centroid_cal...

184 lines
7.9 KiB
Python

from pathlib import Path
from zipfile import ZipFile, ZIP_DEFLATED
import html
import shutil
import xml.etree.ElementTree as ET
BASE_DIR = Path(__file__).resolve().parent
INPUT_DOCX = BASE_DIR / "Penjelasan_Rinci_KMeans_Rekomendasi_JMW_Gabungan_Update.docx"
OUTPUT_DOCX = BASE_DIR / "Penjelasan_Rinci_KMeans_Rekomendasi_JMW_Gabungan_Update_Centroid.docx"
W_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
ET.register_namespace("w", W_NS)
def qn(tag):
return f"{{{W_NS}}}{tag}"
def paragraph(text, style=None, bold=False):
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)
r = ET.SubElement(p, qn("r"))
if bold:
r_pr = ET.SubElement(r, qn("rPr"))
ET.SubElement(r_pr, qn("b"))
t = ET.SubElement(r, qn("t"))
t.text = text
return p
def table(rows):
tbl = ET.Element(qn("tbl"))
tbl_pr = ET.SubElement(tbl, qn("tblPr"))
tbl_style = ET.SubElement(tbl_pr, qn("tblStyle"))
tbl_style.set(qn("val"), "TableGrid")
tbl_w = ET.SubElement(tbl_pr, qn("tblW"))
tbl_w.set(qn("w"), "0")
tbl_w.set(qn("type"), "auto")
for row_index, row in enumerate(rows):
tr = ET.SubElement(tbl, qn("tr"))
for cell in row:
tc = ET.SubElement(tr, qn("tc"))
tc_pr = ET.SubElement(tc, qn("tcPr"))
tc_w = ET.SubElement(tc_pr, qn("tcW"))
tc_w.set(qn("w"), "2400")
tc_w.set(qn("type"), "dxa")
tc.append(paragraph(str(cell), bold=(row_index == 0)))
return tbl
def append_to_docx():
if not INPUT_DOCX.exists():
raise FileNotFoundError(f"Dokumen sumber tidak ditemukan: {INPUT_DOCX}")
shutil.copyfile(INPUT_DOCX, OUTPUT_DOCX)
with ZipFile(INPUT_DOCX, "r") as zin:
document_xml = zin.read("word/document.xml")
files = {name: zin.read(name) for name in zin.namelist() if name != "word/document.xml"}
root = ET.fromstring(document_xml)
body = root.find(qn("body"))
sect_pr = body.find(qn("sectPr"))
insert_index = list(body).index(sect_pr) if sect_pr is not None else len(list(body))
content = []
content.append(paragraph("18. Perhitungan Manual Centroid Awal Sesuai Sistem", style="Heading1"))
content.append(paragraph(
"Pada sistem rekomendasi mobil JMW, centroid awal tidak dipilih secara acak. "
"Kode pada Flask API terlebih dahulu mengurutkan data mobil berdasarkan harga, "
"kemudian memilih beberapa data yang posisinya tersebar dari harga terendah sampai harga tertinggi. "
"Data yang dipilih tersebut dijadikan centroid awal dalam bentuk vector normalisasi."
))
content.append(paragraph(
"Atribut yang digunakan dalam proses clustering pada sistem adalah harga, tahun, dan mesin_cc. "
"Sebelum menjadi centroid, setiap nilai atribut dinormalisasi terlebih dahulu menggunakan Min-Max Normalization "
"agar semua atribut berada pada rentang 0 sampai 1."
))
content.append(paragraph("Rumus normalisasi yang digunakan:", bold=True))
content.append(paragraph("X' = (X - nilai minimum) / (nilai maksimum - nilai minimum)"))
content.append(paragraph("Rumus pemilihan posisi centroid awal pada sistem:", bold=True))
content.append(paragraph("posisi = round(cluster_index * (jumlah_data - 1) / (jumlah_cluster - 1))"))
content.append(paragraph(
"Contoh berikut menggunakan jumlah cluster k=4 sesuai nilai yang saat ini dikirim oleh Laravel ke Flask API. "
"Jika sistem diubah menjadi k=6, rumusnya tetap sama, tetapi centroid awal yang dipilih berjumlah 6 data."
))
content.append(paragraph("Contoh data mobil yang sudah layak dipakai clustering:", bold=True))
raw_rows = [
["Mobil", "Harga", "Tahun", "Mesin CC"],
["Hyundai Ioniq", "122.000.000", "2021", "1197"],
["Toyota Avanza", "125.000.000", "2019", "1500"],
["Toyota Innova", "250.000.000", "2020", "2000"],
["Toyota Fortuner", "500.000.000", "2021", "2500"],
]
content.append(table(raw_rows))
content.append(paragraph(
"Dari contoh data tersebut, nilai minimum dan maksimum setiap atribut adalah: "
"harga minimum 122.000.000 dan harga maksimum 500.000.000; tahun minimum 2019 dan tahun maksimum 2021; "
"mesin minimum 1197 cc dan mesin maksimum 2500 cc."
))
content.append(paragraph("Hasil normalisasi setiap data:", bold=True))
norm_rows = [
["Mobil", "Harga Normalisasi", "Tahun Normalisasi", "Mesin Normalisasi", "Vector Normalisasi"],
["Hyundai Ioniq", "0,000", "1,000", "0,000", "[0,000; 1,000; 0,000]"],
["Toyota Avanza", "0,008", "0,000", "0,233", "[0,008; 0,000; 0,233]"],
["Toyota Innova", "0,339", "0,500", "0,616", "[0,339; 0,500; 0,616]"],
["Toyota Fortuner", "1,000", "1,000", "1,000", "[1,000; 1,000; 1,000]"],
]
content.append(table(norm_rows))
content.append(paragraph("Contoh perhitungan normalisasi:", bold=True))
content.append(paragraph(
"Harga Toyota Avanza = (125.000.000 - 122.000.000) / (500.000.000 - 122.000.000) "
"= 3.000.000 / 378.000.000 = 0,008."
))
content.append(paragraph(
"Tahun Toyota Avanza = (2019 - 2019) / (2021 - 2019) = 0 / 2 = 0,000."
))
content.append(paragraph(
"Mesin Toyota Avanza = (1500 - 1197) / (2500 - 1197) = 303 / 1303 = 0,233."
))
content.append(paragraph(
"Maka vector normalisasi Toyota Avanza adalah [0,008; 0,000; 0,233]. "
"Vector inilah yang digunakan sistem untuk menghitung jarak ke centroid."
))
content.append(paragraph("Perhitungan posisi centroid awal untuk k=4:", bold=True))
content.append(paragraph("Jumlah data = 4, jumlah cluster = 4."))
centroid_rows = [
["Cluster", "cluster_index", "Perhitungan Posisi", "Posisi", "Centroid Awal"],
["C1", "0", "round(0 * (4 - 1) / (4 - 1))", "0", "Hyundai Ioniq"],
["C2", "1", "round(1 * (4 - 1) / (4 - 1))", "1", "Toyota Avanza"],
["C3", "2", "round(2 * (4 - 1) / (4 - 1))", "2", "Toyota Innova"],
["C4", "3", "round(3 * (4 - 1) / (4 - 1))", "3", "Toyota Fortuner"],
]
content.append(table(centroid_rows))
content.append(paragraph(
"Berdasarkan perhitungan tersebut, centroid awal yang digunakan adalah vector normalisasi dari data pada posisi 0, 1, 2, dan 3."
))
final_rows = [
["Centroid", "Vector Centroid Awal"],
["C1", "[0,000; 1,000; 0,000]"],
["C2", "[0,008; 0,000; 0,233]"],
["C3", "[0,339; 0,500; 0,616]"],
["C4", "[1,000; 1,000; 1,000]"],
]
content.append(table(final_rows))
content.append(paragraph(
"Setelah centroid awal terbentuk, sistem menghitung jarak setiap mobil ke semua centroid menggunakan Euclidean Distance. "
"Mobil akan masuk ke cluster yang memiliki jarak paling dekat. Setelah semua data masuk ke cluster, sistem menghitung ulang centroid baru "
"berdasarkan rata-rata vector anggota cluster. Proses ini diulang sampai jumlah iterasi selesai atau posisi cluster tidak banyak berubah."
))
content.append(paragraph(
"Dengan demikian, centroid awal pada sistem bukan angka yang dibuat manual oleh pengguna, tetapi berasal dari data mobil yang sudah dinormalisasi. "
"Pemilihan awalnya mengikuti urutan harga agar centroid mewakili sebaran harga dari rendah sampai tinggi, lalu atribut tahun dan mesin tetap ikut mempengaruhi "
"jarak dan pembentukan cluster."
))
for offset, element in enumerate(content):
body.insert(insert_index + offset, element)
new_xml = ET.tostring(root, encoding="utf-8", xml_declaration=True)
with ZipFile(OUTPUT_DOCX, "w", ZIP_DEFLATED) as zout:
for name, data in files.items():
zout.writestr(name, data)
zout.writestr("word/document.xml", new_xml)
print(OUTPUT_DOCX)
if __name__ == "__main__":
append_to_docx()