Data Wrangling & Exploratory Data Analysis
Hands-on preprocessing dan eksplorasi data drilling menggunakan Python. Pelajari teknik pembersihan data, transformasi, dan visualisasi untuk analisis geofisika.
- Melakukan loading dan inspeksi data drilling dengan Python
- Mengidentifikasi dan menangani missing values & duplikat
- Melakukan transformasi dan feature engineering pada data geofisika
- Membuat visualisasi data geofisika (well log style plot)
- Menganalisis korelasi antar parameter drilling
- Menginterpretasikan hasil EDA dalam konteks geofisika
Dataset Praktikum
Well Drilling Dataset - 2,060 records dengan 14 variabel drilling parameters
Pendahuluan & Dataset
Pada praktikum ini, kita akan bekerja dengan data drilling/MWD (Measurement While Drilling) dari operasi pengeboran sumur minyak dan gas. Data MWD sangat penting dalam industri migas karena memberikan informasi real-time tentang kondisi pengeboran dan karakteristik formasi batuan.
๐ Deskripsi Parameter
TMD / TVD (m)
True Measured Depth / True Vertical Depth
ROP (m/hr)
Rate of Penetration - Kecepatan pengeboran
WOB (ton)
Weight on Bit - Beban pada mata bor
FR (gpm)
Flow Rate - Laju alir lumpur pemboran
SPP (psi)
Standpipe Pressure - Tekanan pipa tegak
RPM (rpm)
Rotation per Minute - Kecepatan putaran
TQ (lb.ft)
Torque - Momen putar
MW IN/OUT (ppg)
Mud Weight - Densitas lumpur masuk/keluar
Loading & Inspeksi Data
Langkah pertama adalah memuat data dan memahami strukturnya menggunakan Pandas.
# Import library yang diperlukan import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns plt.style.use('dark_background') print("โ Library berhasil di-import!")
โ Library berhasil di-import!
# Membaca dataset df = pd.read_csv('Well_Dataset.csv') print(f"Dimensi Data: {df.shape[0]:,} baris ร {df.shape[1]} kolom")
Dimensi Data: 2,060 baris ร 14 kolom
# Melihat 5 baris pertama df.head()
| Formation | TMD | TVD | ROP | WOB | FR | SPP | RPM | TQ | MW IN | MW OUT | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Seno | 428 | 428.01 | 33.3 | 3 | 514.3 | 818 | 70.0 | 1915.0 | 10.4 | 10.401 |
| 1 | Seno | 428 | 428.01 | 33.3 | 3 | 514.3 | 818 | 70.0 | 1915.0 | 10.4 | 10.401 |
| 2 | Seno | 429 | 429.01 | 39.3 | 4 | 428.8 | 554 | 79.0 | 2383.0 | 10.4 | 10.403 |
# Melihat formasi unik print("๐ท๏ธ Formasi yang Ditembus:") for f in df['Formation'].unique(): print(f" โข {f}: {len(df[df['Formation']==f]):,} pts")
๐ท๏ธ Formasi yang Ditembus: โข Seno: 342 pts โข Turo: 89 pts โข Ceno: 203 pts โข Albi: 213 pts โข Apti: 36 pts โข Barre: 411 pts โข Neo: 265 pts โข Malcolm: 205 pts โข Eren Shale: 252 pts โข Mikasa Anhydrite: 44 pts
Dataset memiliki 2,060 data points dengan 14 kolom.
Handling Missing Values
# Identifikasi missing values missing = df.isnull().sum() print("โ Missing Values:") for col in df.columns: if missing[col] > 0: print(f" โ ๏ธ {col}: {missing[col]}")
โ Missing Values: โ ๏ธ RPM (rpm): 1 โ ๏ธ TQ (lb.ft): 1
Gambar 1. Visualisasi Missing Values per Kolom
# Interpolasi linear untuk mengisi missing values df['RPM (rpm)'] = df['RPM (rpm)'].interpolate(method='linear') df['TQ (lb.ft)'] = df['TQ (lb.ft)'].interpolate(method='linear') print("โ Missing values setelah interpolasi: 0")
โ Missing values setelah interpolasi: 0
Untuk data time-series, interpolasi linear adalah pilihan yang baik karena mempertahankan kontinuitas data.
Handling Duplicates
# Menghitung dan menghapus duplikat duplicates = df.duplicated().sum() print(f"๐ Jumlah baris duplikat: {duplicates}") df = df.drop_duplicates(keep='first').reset_index(drop=True) print(f"๐ Jumlah baris setelah cleaning: {len(df):,}")
๐ Jumlah baris duplikat: 2 ๐ Jumlah baris setelah cleaning: 2,058
Gambar 2. Visualisasi Duplicated Values
Data Transformation & Feature Engineering
# Konversi datetime df['DATE TIME'] = pd.to_datetime(df['DATE TIME'], format='%d/%m/%Y %H.%M.%S') print("๐ Rentang Waktu:") print(f" Mulai : {df['DATE TIME'].min()}") print(f" Selesai: {df['DATE TIME'].max()}")
๐ Rentang Waktu: Mulai : 2010-06-19 07:12:15 Selesai: 2010-06-23 01:37:16
# Feature Engineering df['MW_DIFF'] = df['MW OUT (ppg)'] - df['MW IN (ppg)'] df['DEPTH_CAT'] = pd.cut(df['TVD (m)'], bins=[0, 1000, 1500, 2000, 3000], labels=['Shallow', 'Medium', 'Deep', 'Very Deep']) df['FORMATION_CODE'] = df['Formation'].astype('category').cat.codes print("โ Feature baru: MW_DIFF, DEPTH_CAT, FORMATION_CODE")
โ Feature baru: MW_DIFF, DEPTH_CAT, FORMATION_CODE
Statistik Deskriptif
# Statistik deskriptif df[['ROP (m/hr)', 'WOB (ton)', 'RPM (rpm)', 'TQ (lb.ft)']].describe().round(2)
| ROP (m/hr) | WOB (ton) | RPM (rpm) | TQ (lb.ft) | |
|---|---|---|---|---|
| count | 2058.00 | 2058.00 | 2058.00 | 2058.00 |
| mean | 72.53 | 8.74 | 156.32 | 9212.15 |
| std | 32.63 | 3.59 | 23.92 | 3172.58 |
| min | 3.10 | 0.00 | 70.00 | 784.00 |
| 50% | 67.20 | 9.00 | 158.00 | 9148.00 |
| max | 203.20 | 22.00 | 199.00 | 19822.00 |
# Rata-rata ROP per formasi rop_by_formation = df.groupby('Formation')['ROP (m/hr)'].mean().sort_values(ascending=False) print(rop_by_formation.round(2))
Formation Neo 93.17 Albi 88.93 Ceno 84.38 Turo 82.47 Seno 67.63 Barre 66.43 Malcolm 54.48 Eren Shale 41.16 Apti 35.44 Mikasa Anhydrite 21.73
Formasi Neo memiliki ROP tertinggi (93.17 m/hr) = formasi lunak. Mikasa Anhydrite ROP terendah (21.73 m/hr) = batuan sangat keras.
Visualisasi Data
๐ 7.1 Distribusi Parameter
# Histogram distribusi parameter drilling fig, axes = plt.subplots(2, 3, figsize=(14, 8)) params = ['ROP (m/hr)', 'WOB (ton)', 'RPM (rpm)', 'TQ (lb.ft)', 'SPP (psi)', 'FR (gpm)'] for ax, param in zip(axes.flatten(), params): ax.hist(df[param], bins=30, color='#e94560') plt.tight_layout(); plt.show()

๐ฆ 7.2 Boxplot per Formasi
# Boxplot per formasi fig, axes = plt.subplots(2, 2, figsize=(14, 10)) for ax, param in zip(axes.flatten(), ['ROP (m/hr)', 'WOB (ton)', 'RPM (rpm)', 'TQ (lb.ft)']): df.boxplot(column=param, by='Formation', ax=ax) plt.show()

๐ 7.3 Well Log Style Plot
# Well Log Style Plot - Parameter vs Kedalaman fig, axes = plt.subplots(1, 5, figsize=(16, 12), sharey=True) params = ['ROP (m/hr)', 'WOB (ton)', 'RPM (rpm)', 'TQ (lb.ft)', 'SPP (psi)'] for ax, param in zip(axes, params): ax.plot(df[param], df['TVD (m)']) ax.fill_betweenx(df['TVD (m)'], 0, df[param], alpha=0.3) axes[0].invert_yaxis() plt.show()

Well log plot menampilkan parameter vs kedalaman (sumbu Y terbalik). Perubahan mendadak sering mengindikasikan batas formasi.
๐ฅง 7.4 Distribusi Formasi
# Distribusi dan rata-rata ROP per formasi fig, axes = plt.subplots(1, 2, figsize=(14, 6)) df['Formation'].value_counts().plot.pie(ax=axes[0], autopct='%1.1f%%') df.groupby('Formation')['ROP (m/hr)'].mean().sort_values().plot.barh(ax=axes[1]) plt.show()

๐ 7.5 Time Series
# Time series plot fig, axes = plt.subplots(3, 1, figsize=(14, 10), sharex=True) axes[0].plot(df['DATE TIME'], df['ROP (m/hr)'], color='#e94560') axes[1].plot(df['DATE TIME'], df['WOB (ton)'], color='#00d9ff') axes[2].plot(df['DATE TIME'], df['TQ (lb.ft)'], color='#4ecdc4') plt.tight_layout(); plt.show()

Analisis Korelasi
# Correlation heatmap cols = ['ROP (m/hr)', 'WOB (ton)', 'FR (gpm)', 'SPP (psi)', 'RPM (rpm)', 'TQ (lb.ft)', 'TVD (m)'] corr = df[cols].corr() plt.figure(figsize=(12, 10)) sns.heatmap(corr, annot=True, cmap='RdBu_r', center=0) plt.show()

# Scatter plots fig, axes = plt.subplots(1, 3, figsize=(15, 5)) axes[0].scatter(df['WOB (ton)'], df['ROP (m/hr)'], c=df['TVD (m)'], cmap='plasma', s=10) axes[1].scatter(df['RPM (rpm)'], df['ROP (m/hr)'], c=df['TVD (m)'], cmap='plasma', s=10) axes[2].scatter(df['WOB (ton)'], df['TQ (lb.ft)'], c=df['TVD (m)'], cmap='plasma', s=10) plt.tight_layout(); plt.show()

โข SPP vs TVD (+0.81): Tekanan meningkat dengan kedalaman
โข TQ vs WOB (+0.36): Torsi meningkat dengan beban
โข ROP vs TVD (-0.43): ROP menurun dengan kedalaman (formasi makin keras)
Insight & Kesimpulan
1. Kualitas Data
Dataset relatif bersih dengan hanya 2 missing values (0.05%) dan 2 duplikat. Setelah cleaning: 2,058 baris.
2. Karakteristik Formasi
โข Formasi Lunak: Neo, Albi, Ceno, Turo (ROP > 80 m/hr)
โข Formasi Sedang: Seno, Barre (ROP 60-70 m/hr)
โข Formasi Keras: Malcolm, Eren Shale, Apti, Mikasa Anhydrite (ROP < 55 m/hr)
3. Hubungan Parameter
SPP berkorelasi kuat dengan kedalaman (+0.81). ROP menurun seiring kedalaman. Torsi berkorelasi positif dengan WOB.
4. Rekomendasi untuk ML
Dataset cocok untuk: klasifikasi formasi, prediksi ROP, dan segmentasi zona drilling.
# Simpan dataset yang sudah dibersihkan df.to_csv('Well_Dataset_Clean.csv', index=False) print("โ Dataset disimpan: Well_Dataset_Clean.csv") print(f" Baris: {len(df):,} | Kolom: {len(df.columns)}")
โ Dataset disimpan: Well_Dataset_Clean.csv Baris: 2,058 | Kolom: 17
Latihan Mandiri
- Missing Values Analysis
Jika dataset memiliki 10% missing values pada kolom ROP, strategi apa yang paling tepat? Jelaskan dan implementasikan dengan kode. - Feature Engineering
Buat fitur baru "DRILLING_EFFICIENCY" = ROP / (WOB ร RPM). Analisis distribusinya per formasi. - Outlier Detection
Identifikasi outlier pada kolom TQ menggunakan metode IQR. Berapa persen data yang termasuk outlier? - Analisis Zona
Filter data hanya untuk kedalaman 1000-1500m. Bandingkan statistiknya dengan keseluruhan data. - Cross-plot Analysis
Buat cross-plot WOB vs ROP dengan warna berbeda untuk setiap formasi. Interpretasikan pola yang terlihat.
Kerjakan soal latihan dalam format Jupyter Notebook (.ipynb). Sertakan kode, output, dan interpretasi untuk setiap soal. Submit melalui e-learning sebelum pertemuan berikutnya.