Difference between revisions of "Data-cleaning-fisip"
| Line 798: | Line 798: | ||
| + | ==Link Terkait== | ||
* [[Big Data Fisip]] | * [[Big Data Fisip]] | ||
Latest revision as of 14:05, 30 September 2026
Dari contoh yang didapat, kita akan melakukan hal berikut
bluesky_climate_change_raw.csv
↓
DATA CLEANING
↓
PREPROCESSING
↓
bluesky_climate_change_clean.csv
↓
ANALISIS
Step by step nya adalah
Contents
Data Cleaning
Import library dan membaca data
import pandas as pd
import re
df = pd.read_csv(
"bluesky_climate_change_raw.csv"
)
df.head()
Cek ukuran data
df.shape
Klo di contoh saya nanti hasilnya adalah (97, 9). Artinya: 97 baris × 9 variabel.
Cek nama variabel
df.columns
Cek kondisi data
df.info() df.head() df.sample(5) df.isna().sum()
Untuk kasus saya, ada 15 posting tidak mempunyai display_name, namun kita cek pakah masih memiliki username
df["display_name"] = (
df["display_name"]
.fillna(df["username"])
)
Kemudian cek lagi
df["display_name"].isna().sum()
Harus menghasilkan 0
Berarti dalam kasus ini display_name tidak terlalu penting karena masih ada username.
Cek apakah ada duplicate
df.duplicated().sum()
Klo pada kasus saya, id unik nya adalah uri,jadi
df.duplicated(
subset="uri"
).sum()
Kode cleaning nya adalah
df = df.drop_duplicates(
subset="uri"
)
Kalau satu posting masuk dua kali, analisis kita dapat menghitung satu opini atau satu engagement dua kali.
Rapihkan display_name
Beberapa nama mungkin memiliki spasi tambahan.
df["display_name"] = (
df["display_name"]
.astype(str)
.str.strip()
)
Kita rapihkan juga username
df["username"] = (
df["username"]
.astype(str)
.str.strip()
.str.lower()
)
Perbaiki type tanggal
Kita cek tipe datanya
df["created_at"].dtype
Jika hasilnya = object, berarti masih dianggap teks, jadi harus diubah ke tipe waktu.
df["created_at"] = pd.to_datetime(
df["created_at"],
format="mixed",
utc=True,
errors="coerce"
)
Ubah UTC ke waktu Jakarta
df["created_at_wib"] = (
df["created_at"]
.dt.tz_convert("Asia/Jakarta")
)
Kemudian cek
df[
["created_at", "created_at_wib"]
].head()
Rapihkan kolom bahasa
df["language"].value_counts()
Perbaiki
df["language_primary"] = (
df["language"]
.astype(str)
.str.extract(
r"([A-Za-z]+(?:-[A-Za-z]+)?)",
expand=False
)
.fillna("unknown")
)
Cek
df["language_primary"].value_counts()
Pastikan reply, repost dan like benar-benar numerik
Cek
df[
[
"reply_count",
"repost_count",
"like_count"
]
].dtypes
Jika masih belum angka
kolom_angka = [
"reply_count",
"repost_count",
"like_count"
]
for kolom in kolom_angka:
df[kolom] = pd.to_numeric(
df[kolom],
errors="coerce"
).fillna(0).astype(int)
Jika ada URL terambil
Buat variabel, barangkali nanti url tersebut dibutuhkan
df["has_url"] = (
df["text"]
.str.contains(
r"https?://|www\.",
regex=True,
na=False
)
)
Cek
df["has_url"].value_counts()
Deteksi Hastag
df["has_hashtag"] = (
df["text"]
.str.contains(
r"#\w+",
regex=True,
na=False
)
)
Cek
df["has_hashtag"].value_counts()
Preprocessing
Buat Clean Text
Kita mulai masuk ke preprocessing
df["text_clean"] = (
df["text"]
.fillna("")
.astype(str)
)
Hapus URL
df["text_clean"] = (
df["text_clean"]
.str.replace(
r"https?://\S+|www\.\S+",
" ",
regex=True
)
)
Nanti hasilnya misal: Climate change is real https://example.com -> Climate change is real
Hilangkan mention
df["text_clean"] = (
df["text_clean"]
.str.replace(
r"@[\w.-]+",
" ",
regex=True
)
)
Namun mention tidak selalu harus dibuang. Kalau kita ingin melakukan network analysis, mention justru merupakan data yang penting.
Hastag
Jangan buang katanya, namun tanda "#" saja
df["text_clean"] = (
df["text_clean"]
.str.replace(
r"#(\w+)",
r"\1",
regex=True
)
)
Ubah menjadi lowercase
df["text_clean"] = (
df["text_clean"]
.str.lower()
)
Ini penting agar komputer tidak menganggap kata yang sama namun misal ada huruf kapital, sebagai kata berbeda.
Rapikan line break dan spasi
df["text_clean"] = (
df["text_clean"]
.str.replace(
r"\s+",
" ",
regex=True
)
.str.strip()
)
Bandingkan sebelum dan sesudah
df[
[
"text",
"text_clean"
]
].head(10)
Buat variabel engagement
Misal kita perlu untuk menghitung hubungannya. Kita definisikan secara sederhana:Engagement = Reply + Repost + Like
df["engagement"] = (
df["reply_count"]
+ df["repost_count"]
+ df["like_count"]
)
Kita cek
df[
[
"reply_count",
"repost_count",
"like_count",
"engagement"
]
].head()
Ini adalah definisi operasional untuk latihan, bukan definisi universal engagement. Kalau penelitian sebenarnya, Anda harus menjelaskan mengapa reply, repost, dan like dijumlahkan dan apakah bobotnya memang seharusnya sama.
Buat jumlah kata
df["word_count"] = (
df["text_clean"]
.str.findall(
r"\b[\w’'-]+\b"
)
.str.len()
)
Cek
df["word_count"].describe()
Buat variabel tanggal dan jam
df["date"] = (
df["created_at_wib"]
.dt.date
)
df["hour"] = (
df["created_at_wib"]
.dt.hour
)
Cleaning = memperbaiki data. Preprocessing = membuat data menjadi lebih siap untuk analisis.
Validasi
Jumlah data:
len(df)
Missing value:
df.isna().sum()
Duplicate:
df.duplicated(subset="uri").sum()
Statistik engagement:
df["engagement"].describe()
Tampilkan hasil:
df.head()
Kode berhasil dijalankan belum berarti data sudah benar. Kita tetap harus memeriksa hasil.
Simpan
df.to_csv(
"bluesky_climate_change_clean.csv",
index=False,
encoding="utf-8"
)
Kode lengkap
import pandas as pd
import re
# ==========================================
# 1. LOAD DATA
# ==========================================
df = pd.read_csv(
"bluesky_climate_change_raw.csv"
)
# ==========================================
# 2. DUPLICATE
# ==========================================
df = df.drop_duplicates(
subset="uri"
)
# ==========================================
# 3. MISSING DISPLAY NAME
# ==========================================
df["display_name"] = (
df["display_name"]
.fillna(df["username"])
.astype(str)
.str.strip()
)
df["username"] = (
df["username"]
.astype(str)
.str.strip()
.str.lower()
)
# ==========================================
# 4. DATE / TIME
# ==========================================
df["created_at"] = pd.to_datetime(
df["created_at"],
format="mixed",
utc=True,
errors="coerce"
)
df["created_at_wib"] = (
df["created_at"]
.dt.tz_convert("Asia/Jakarta")
)
# ==========================================
# 5. LANGUAGE
# ==========================================
df["language_primary"] = (
df["language"]
.astype(str)
.str.extract(
r"([A-Za-z]+(?:-[A-Za-z]+)?)",
expand=False
)
.fillna("unknown")
)
# ==========================================
# 6. NUMERIC VARIABLES
# ==========================================
kolom_angka = [
"reply_count",
"repost_count",
"like_count"
]
for kolom in kolom_angka:
df[kolom] = pd.to_numeric(
df[kolom],
errors="coerce"
).fillna(0).astype(int)
# ==========================================
# 7. INFORMATION FROM ORIGINAL TEXT
# ==========================================
df["has_url"] = (
df["text"]
.str.contains(
r"https?://|www\.",
regex=True,
na=False
)
)
df["has_hashtag"] = (
df["text"]
.str.contains(
r"#\w+",
regex=True,
na=False
)
)
# ==========================================
# 8. TEXT CLEANING
# ==========================================
df["text_clean"] = (
df["text"]
.fillna("")
.astype(str)
)
# Remove URL
df["text_clean"] = (
df["text_clean"]
.str.replace(
r"https?://\S+|www\.\S+",
" ",
regex=True
)
)
# Remove mentions
df["text_clean"] = (
df["text_clean"]
.str.replace(
r"@[\w.-]+",
" ",
regex=True
)
)
# Keep hashtag word, remove #
df["text_clean"] = (
df["text_clean"]
.str.replace(
r"#(\w+)",
r"\1",
regex=True
)
)
# Lowercase
df["text_clean"] = (
df["text_clean"]
.str.lower()
)
# Remove extra whitespace
df["text_clean"] = (
df["text_clean"]
.str.replace(
r"\s+",
" ",
regex=True
)
.str.strip()
)
# ==========================================
# 9. DERIVED VARIABLES
# ==========================================
df["engagement"] = (
df["reply_count"]
+ df["repost_count"]
+ df["like_count"]
)
df["word_count"] = (
df["text_clean"]
.str.findall(
r"\b[\w’'-]+\b"
)
.str.len()
)
df["date"] = (
df["created_at_wib"]
.dt.date
)
df["hour"] = (
df["created_at_wib"]
.dt.hour
)
# ==========================================
# 10. VALIDATION
# ==========================================
print("Jumlah data:", len(df))
print(
"\nMissing value:"
)
print(
df.isna().sum()
)
print(
"\nDuplicate URI:",
df.duplicated(
subset="uri"
).sum()
)
print(
"\nStatistik engagement:"
)
print(
df["engagement"].describe()
)
# ==========================================
# 11. SAVE
# ==========================================
df.to_csv(
"bluesky_climate_change_clean.csv",
index=False,
encoding="utf-8"
)
print(
"\nData bersih berhasil disimpan."
)
Analisis yang bisa dilakukan
Seberapa tinggi engagement?
df["engagement"].describe()
Posting dengan engagement tertinggi
top10 = (
df.sort_values(
"engagement",
ascending=False
)
[
[
"username",
"text_clean",
"reply_count",
"repost_count",
"like_count",
"engagement"
]
]
.head(10)
)
top10
Visualisasi Top 10 Engagement
import matplotlib.pyplot as plt
top10_plot = (
df.nlargest(
10,
"engagement"
)
.sort_values(
"engagement"
)
)
top10_plot.plot(
x="username",
y="engagement",
kind="barh",
legend=False
)
plt.title(
"10 Posting dengan Engagement Tertinggi"
)
plt.xlabel(
"Engagement"
)
plt.ylabel(
"Akun"
)
plt.show()
Akun paling aktif
df[
"username"
].value_counts().head(10)
Aktivitas berdasarkan jam
posting_per_jam = (
df["hour"]
.value_counts()
.sort_index()
)
posting_per_jam
Visualisasi
posting_per_jam.plot(
kind="bar"
)
plt.title(
"Jumlah Posting per Jam"
)
plt.xlabel(
"Jam (WIB)"
)
plt.ylabel(
"Jumlah Posting"
)
plt.show()
Kata yang sering muncul
from collections import Counter
semua_teks = " ".join(
df["text_clean"]
)
kata = re.findall(
r"[a-zA-Z][a-zA-Z'-]+",
semua_teks
)
stopwords = {
"the", "and", "to", "of",
"a", "in", "is", "for",
"that", "it", "on", "with",
"are", "be", "as", "this",
"we", "i", "you", "they",
"have", "has", "was",
"were", "not", "but",
# kata pencarian
"climate",
"change",
"climatechange"
}
kata_bersih = [
k
for k in kata
if k not in stopwords
and len(k) > 2
]
frekuensi = Counter(
kata_bersih
)
frekuensi.most_common(20)
Visualisasi 15 kata teratas
freq_df = pd.DataFrame(
frekuensi.most_common(15),
columns=[
"word",
"frequency"
]
)
freq_df = freq_df.sort_values(
"frequency"
)
freq_df.plot(
x="word",
y="frequency",
kind="barh",
legend=False
)
plt.title(
"15 Kata yang Sering Muncul"
)
plt.xlabel(
"Frekuensi"
)
plt.ylabel(
"Kata"
)
plt.show()