Difference between revisions of "Data-cleaning-fisip"

From belajarwiki
Jump to navigation Jump to search
 
(One intermediate revision by the same user not shown)
Line 796: Line 796:
 
plt.show()
 
plt.show()
 
</pre>
 
</pre>
 +
 +
 +
==Link Terkait==
 +
* [[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

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()


Link Terkait