Bagian 2 menghasilkan angka; bagian ini memperlihatkan bentuknya. Grafik bukan hiasan laporan — histogram menunjukkan wujud sebaran yang hanya tersirat pada selisih mean-median, box plot mengekspos outlier yang selama ini berupa z = 4.68, scatter plot menguji apakah hubungan linear r = 0.775 memang tampak sebagai garis, dan diagram batang membuat selisih antar departemen terlihat dalam sekali pandang. Kita memakai pola kerja chapter Visualisasi dengan matplotlib: backend Agg tanpa layar, savefig disertai plt.close(), serta label dan judul pada setiap sumbu. Empat grafik digambar dari dataset bersih 29 baris yang sama, dan setiap blok mencetak angka pemeriksaan silang — frekuensi, median, atau slope — sehingga grafik dan angka saling mengunci.

Histogram Sebaran Gaji #

Histogram membagi rentang gaji menjadi enam kelas dengan bins=6, menghitung banyaknya karyawan di tiap kelas, lalu menggambarkannya sebagai batang bersambung. Nilai kembalian plt.hist menyimpan frekuensi dan batas kelas — angka yang sama dengan tabel frekuensi manual dari chapter Tabel Frekuensi:

python
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import pandas as pd
import io

csv_bersih = """id,nama,departemen,umur,masa_kerja,gaji,skor_kinerja
P001,Budi Santoso,Produksi,34,6,11.5,79
P002,Agus Wijaya,Produksi,28,3,9.4,74
P003,Joko Prasetyo,Produksi,41,12,14.6,81
P004,Tono Hartono,Produksi,25,1,8.0,70
P005,Eko Saputra,Produksi,38,9,13.5,83
P006,Hendra Gunawan,Produksi,31,5,10.8,77
P007,Udin Samsudin,Produksi,46,16,16.2,80
P008,Wahyu Nugroho,Produksi,52,20,18.8,85
P009,Yanto Kurniawan,Produksi,24,2,8.7,72
P010,Siti Rahmawati,Keuangan,35,8,12.0,76
P011,Dewi Lestari,Keuangan,29,4,9.8,73
P012,Rina Marlina,Keuangan,33.5,6,11.0,75
P013,Fajar Ramadhan,Keuangan,42,14,15.0,78
P014,Indra Maulana,Keuangan,33,7,11.2,74
P015,Prakasa Wibowo,Keuangan,56,22,45.0,88
P016,Maya Anggraini,Pemasaran,30,5,12.3,86
P017,Rian Hidayat,Pemasaran,27,3,11.0,84
P018,Gita Permata,Pemasaran,36,10,14.8,89
P019,Nanda Pratama,Pemasaran,32,7,13.2,87
P020,Citra Kirana,Pemasaran,26,2,10.2,82
P021,Bayu Setiawan,Pemasaran,39,13,16.4,90
P022,Laila Sari,Pemasaran,30,6,12.4,85
P023,Oka Mahendra,Pemasaran,44,18,18.8,91
P024,Tuti Handayani,SDM,37,9,11.7,71
P025,Yuni Astuti,SDM,28,3,8.5,68
P026,Putri Ayu,SDM,33,6,10.2,70
P027,Dedi Kurnia,SDM,40,11,12.4,70
P028,Wawan Susanto,SDM,45,15,14.7,73
P029,Sari Wulandari,SDM,26,1,7.5,67
"""

df = pd.read_csv(io.StringIO(csv_bersih))

plt.figure()
jumlah, batas, _ = plt.hist(df["gaji"], bins=6, edgecolor="black")
plt.xlabel("Gaji (juta Rp)")
plt.ylabel("Jumlah karyawan")
plt.title("Sebaran Gaji 29 Karyawan PT Maju Bersama")
plt.savefig("histogram_gaji.png")
plt.close()

print("frekuensi per kelas :", [int(j) for j in jumlah])
print("batas kelas         :", [f"{b:.2f}" for b in batas])

Output yang Dihasilkan:

text
frekuensi per kelas : [20, 8, 0, 0, 0, 1]
batas kelas         : ['7.50', '13.75', '20.00', '26.25', '32.50', '38.75', '45.00']

Enam kelas masing-masing selebar 6.25 juta, dari batas bawah 7.50 hingga batas atas 45.00. Frekuensi [20, 8, 0, 0, 0, 1] menceritakan bentuk yang khas: batang pertama menjulang dengan 20 karyawan berpengaji 7.50-13.75 juta, turun ke 8 pada kelas kedua, lalu tiga kelas kosong beruntun — tidak ada satu pun gaji di rentang 20.00-38.75 — sebelum satu batang pendek berdiri sendiri di kelas 38.75-45.00. Itulah sebaran condong ke kanan (right-skewed) yang diprediksi Bagian 2: 28 dari 29 karyawan berkumpul di kiri, dan satu gaji direktur menarik ekor distribusi jauh ke kanan sekaligus menaikkan mean di atas median.

Box Plot Gaji per Departemen #

Box plot merangkum tiap departemen dalam lima angka — minimum, kuartil bawah, median, kuartil atas, maksimum — dan menandai nilai yang melampaui whisker sebagai titik pencilan. Empat kelompok dibentuk dari kolom departemen, dan median tiap kelompok dihitung ulang dengan np.median sebagai pemeriksaan silang:

python
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import io

csv_bersih = """id,nama,departemen,umur,masa_kerja,gaji,skor_kinerja
P001,Budi Santoso,Produksi,34,6,11.5,79
P002,Agus Wijaya,Produksi,28,3,9.4,74
P003,Joko Prasetyo,Produksi,41,12,14.6,81
P004,Tono Hartono,Produksi,25,1,8.0,70
P005,Eko Saputra,Produksi,38,9,13.5,83
P006,Hendra Gunawan,Produksi,31,5,10.8,77
P007,Udin Samsudin,Produksi,46,16,16.2,80
P008,Wahyu Nugroho,Produksi,52,20,18.8,85
P009,Yanto Kurniawan,Produksi,24,2,8.7,72
P010,Siti Rahmawati,Keuangan,35,8,12.0,76
P011,Dewi Lestari,Keuangan,29,4,9.8,73
P012,Rina Marlina,Keuangan,33.5,6,11.0,75
P013,Fajar Ramadhan,Keuangan,42,14,15.0,78
P014,Indra Maulana,Keuangan,33,7,11.2,74
P015,Prakasa Wibowo,Keuangan,56,22,45.0,88
P016,Maya Anggraini,Pemasaran,30,5,12.3,86
P017,Rian Hidayat,Pemasaran,27,3,11.0,84
P018,Gita Permata,Pemasaran,36,10,14.8,89
P019,Nanda Pratama,Pemasaran,32,7,13.2,87
P020,Citra Kirana,Pemasaran,26,2,10.2,82
P021,Bayu Setiawan,Pemasaran,39,13,16.4,90
P022,Laila Sari,Pemasaran,30,6,12.4,85
P023,Oka Mahendra,Pemasaran,44,18,18.8,91
P024,Tuti Handayani,SDM,37,9,11.7,71
P025,Yuni Astuti,SDM,28,3,8.5,68
P026,Putri Ayu,SDM,33,6,10.2,70
P027,Dedi Kurnia,SDM,40,11,12.4,70
P028,Wawan Susanto,SDM,45,15,14.7,73
P029,Sari Wulandari,SDM,26,1,7.5,67
"""

df = pd.read_csv(io.StringIO(csv_bersih))

urutan = ["Keuangan", "Pemasaran", "Produksi", "SDM"]
kelompok = [df.loc[df["departemen"] == d, "gaji"].to_numpy() for d in urutan]

plt.figure()
plt.boxplot(kelompok, tick_labels=urutan)
plt.ylabel("Gaji (juta Rp)")
plt.title("Gaji per Departemen")
plt.savefig("boxplot_gaji.png")
plt.close()

print("median gaji per departemen:")
for d, k in zip(urutan, kelompok):
    print(f"  {d:9s}: {np.median(k):.2f}")

Output yang Dihasilkan:

text
median gaji per departemen:
  Keuangan : 11.60
  Pemasaran: 12.80
  Produksi : 11.50
  SDM      : 10.95

Empat median itu berjarak sempit — 10.95 sampai 12.80 — namun kotak Keuangan menyimpan satu titik pencilan di atasnya: gaji 45.0 milik P015, terpisah dari whisker kotaknya. Whisker atas kotak dihitung dari kuartil atas 14.70 ditambah 1.5 × IQR (IQR gaji 4.50), menghasilkan ambang 21.45; gaji tertinggi di bawah ambang itu adalah 18.8, di situlah whisker Keuangan berakhir, sementara 45.0 dilukiskan sebagai titik tersendiri. Grafik ini membongkar kehati-hatian Bagian 2: rata-rata gaji Keuangan 17.33 juta tampak tinggi pada tabel agregasi, tetapi kotaknya menunjukkan separuh anggota departemen itu justru berpengaji di bawah 11.60 juta — satu direktur menggeser mean, bukan seluruh tim. Perbandingan mean-median keempat kelompok dirangkum berikut:

Departemennmean gajimedian gaji
Keuangan617.3311.60
Pemasaran813.6412.80
Produksi912.3911.50
SDM610.8310.95

Scatter Plot dengan Garis Tren #

Korelasi 0.775 antara gaji dan masa kerja mengklaim hubungan linear; scatter plot mengujinya secara visual. Tiap karyawan menjadi satu titik dengan masa kerja pada sumbu-x dan gaji pada sumbu-y, lalu np.polyfit dengan deg=1 memfit garis lurus terbaik lewat titik-titik itu:

python
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import io

csv_bersih = """id,nama,departemen,umur,masa_kerja,gaji,skor_kinerja
P001,Budi Santoso,Produksi,34,6,11.5,79
P002,Agus Wijaya,Produksi,28,3,9.4,74
P003,Joko Prasetyo,Produksi,41,12,14.6,81
P004,Tono Hartono,Produksi,25,1,8.0,70
P005,Eko Saputra,Produksi,38,9,13.5,83
P006,Hendra Gunawan,Produksi,31,5,10.8,77
P007,Udin Samsudin,Produksi,46,16,16.2,80
P008,Wahyu Nugroho,Produksi,52,20,18.8,85
P009,Yanto Kurniawan,Produksi,24,2,8.7,72
P010,Siti Rahmawati,Keuangan,35,8,12.0,76
P011,Dewi Lestari,Keuangan,29,4,9.8,73
P012,Rina Marlina,Keuangan,33.5,6,11.0,75
P013,Fajar Ramadhan,Keuangan,42,14,15.0,78
P014,Indra Maulana,Keuangan,33,7,11.2,74
P015,Prakasa Wibowo,Keuangan,56,22,45.0,88
P016,Maya Anggraini,Pemasaran,30,5,12.3,86
P017,Rian Hidayat,Pemasaran,27,3,11.0,84
P018,Gita Permata,Pemasaran,36,10,14.8,89
P019,Nanda Pratama,Pemasaran,32,7,13.2,87
P020,Citra Kirana,Pemasaran,26,2,10.2,82
P021,Bayu Setiawan,Pemasaran,39,13,16.4,90
P022,Laila Sari,Pemasaran,30,6,12.4,85
P023,Oka Mahendra,Pemasaran,44,18,18.8,91
P024,Tuti Handayani,SDM,37,9,11.7,71
P025,Yuni Astuti,SDM,28,3,8.5,68
P026,Putri Ayu,SDM,33,6,10.2,70
P027,Dedi Kurnia,SDM,40,11,12.4,70
P028,Wawan Susanto,SDM,45,15,14.7,73
P029,Sari Wulandari,SDM,26,1,7.5,67
"""

df = pd.read_csv(io.StringIO(csv_bersih))

plt.figure()
plt.scatter(df["masa_kerja"], df["gaji"])
plt.xlabel("Masa kerja (tahun)")
plt.ylabel("Gaji (juta Rp)")
plt.title("Masa Kerja terhadap Gaji")

slope, intercept = np.polyfit(df["masa_kerja"], df["gaji"], deg=1)
x_garis = np.array([0, 22])
plt.plot(x_garis, slope * x_garis + intercept, color="red", linestyle="--")
plt.savefig("scatter_gaji.png")
plt.close()

print(f"slope     : {slope:.3f}")
print(f"intercept : {intercept:.3f}")
print(f"prediksi gaji masa kerja 1 tahun  : {slope * 1 + intercept:.2f} juta")
print(f"prediksi gaji masa kerja 10 tahun : {slope * 10 + intercept:.2f} juta")

Output yang Dihasilkan:

text
slope     : 0.905
intercept : 5.822
prediksi gaji masa kerja 1 tahun  : 6.73 juta
prediksi gaji masa kerja 10 tahun : 14.87 juta

Titik-titik bergerak naik dari kiri bawah ke kanan atas — 29 titik dari masa kerja 1 hingga 22 tahun. Garis putus-putus memiliki slope 0.905 dan intercept 5.822: setiap tambahan satu tahun masa kerja rata-rata berselisih 0.905 juta rupiah, dan garis memotong sumbu-y di 5.822 juta. Prediksi garis membaca 6.73 juta pada masa kerja satu tahun dan 14.87 juta pada sepuluh tahun. Perlu jujur dicatat: titik P015 di ujung kanan atas (22 tahun, 45.0 juta) berdaya ungkit besar — jaraknya yang jauh dari pusat data menarik garis ke atas, sehingga slope 0.905 bukan murni cerminan 28 karyawan lainnya. Kuadrat korelasi (0.775² = 0.60) menyatakan sekitar 60 persen variasi gaji sejalan dengan garis ini; 40 persen sisanya — jabatan, departemen, skor — tetap berupa sebaran di sekitar garis. Koefisien polyfit berurutan dari pangkat tertinggi: elemen pertama slope, kedua intercept, konvensi yang telah dibahas pada chapter Regresi dengan Python.

Diagram Batang Rata-rata Skor Kinerja #

Grafik terakhir membandingkan rata-rata skor kinerja antar departemen — angka yang dihitung Bagian 2 lewat groupby, kini ditampilkan sebagai batang. Nilai groupby dikembalikan sebagai Series berindeks nama departemen sehingga sumbu-x dan tinggi batang datang dari hasil agregasi yang sama:

python
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import pandas as pd
import io

csv_bersih = """id,nama,departemen,umur,masa_kerja,gaji,skor_kinerja
P001,Budi Santoso,Produksi,34,6,11.5,79
P002,Agus Wijaya,Produksi,28,3,9.4,74
P003,Joko Prasetyo,Produksi,41,12,14.6,81
P004,Tono Hartono,Produksi,25,1,8.0,70
P005,Eko Saputra,Produksi,38,9,13.5,83
P006,Hendra Gunawan,Produksi,31,5,10.8,77
P007,Udin Samsudin,Produksi,46,16,16.2,80
P008,Wahyu Nugroho,Produksi,52,20,18.8,85
P009,Yanto Kurniawan,Produksi,24,2,8.7,72
P010,Siti Rahmawati,Keuangan,35,8,12.0,76
P011,Dewi Lestari,Keuangan,29,4,9.8,73
P012,Rina Marlina,Keuangan,33.5,6,11.0,75
P013,Fajar Ramadhan,Keuangan,42,14,15.0,78
P014,Indra Maulana,Keuangan,33,7,11.2,74
P015,Prakasa Wibowo,Keuangan,56,22,45.0,88
P016,Maya Anggraini,Pemasaran,30,5,12.3,86
P017,Rian Hidayat,Pemasaran,27,3,11.0,84
P018,Gita Permata,Pemasaran,36,10,14.8,89
P019,Nanda Pratama,Pemasaran,32,7,13.2,87
P020,Citra Kirana,Pemasaran,26,2,10.2,82
P021,Bayu Setiawan,Pemasaran,39,13,16.4,90
P022,Laila Sari,Pemasaran,30,6,12.4,85
P023,Oka Mahendra,Pemasaran,44,18,18.8,91
P024,Tuti Handayani,SDM,37,9,11.7,71
P025,Yuni Astuti,SDM,28,3,8.5,68
P026,Putri Ayu,SDM,33,6,10.2,70
P027,Dedi Kurnia,SDM,40,11,12.4,70
P028,Wawan Susanto,SDM,45,15,14.7,73
P029,Sari Wulandari,SDM,26,1,7.5,67
"""

df = pd.read_csv(io.StringIO(csv_bersih))

rata_skor = df.groupby("departemen")["skor_kinerja"].mean()

plt.figure()
plt.bar(rata_skor.index, rata_skor.values, edgecolor="black")
plt.xlabel("Departemen")
plt.ylabel("Rata-rata skor kinerja")
plt.title("Rata-rata Skor Kinerja per Departemen")
plt.savefig("bar_skor.png")
plt.close()

print("rata-rata skor kinerja per departemen:")
print(rata_skor.round(2))

Output yang Dihasilkan:

text
rata-rata skor kinerja per departemen:
departemen
Keuangan     77.33
Pemasaran    86.75
Produksi     77.89
SDM          69.83
Name: skor_kinerja, dtype: float64

Empat batang membentuk tangga yang jelas: Pemasaran menjulang di 86.75, diikuti Produksi 77.89 dan Keuangan 77.33 yang nyaris setinggi, lalu SDM menutup di 69.83 — tertinggal 8.06 poin dari Produksi dan 16.92 poin dari Pemasaran. Sumbu-y dimulai dari nol — kebiasaan kejujuran diagram batang dari chapter Diagram Batang — sehingga rasio tinggi batang mencerminkan rasio skor yang sebenarnya; memotong sumbu di angka 60 akan membuat selisih 16.92 poin tampak berlipat ganda.

Empat grafik telah melengkapi angka Bagian 2 dengan bentuk yang bisa dilihat: sebaran condong kanan, satu pencilan pada kotak Keuangan, awan titik yang menaik dengan garis tren, dan tangga skor antar departemen. Galeri lengkap parameter matplotlib terdokumentasi di matplotlib.org . Bagian terakhir merangkai seluruh alur menjadi satu skrip laporan dan — yang lebih penting — menguji cara membaca temuannya.