<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://kontenbelajar.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Data-cleaning-fisip</id>
	<title>Data-cleaning-fisip - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://kontenbelajar.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Data-cleaning-fisip"/>
	<link rel="alternate" type="text/html" href="https://kontenbelajar.com/wiki/index.php?title=Data-cleaning-fisip&amp;action=history"/>
	<updated>2026-09-29T05:18:30Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.34.1</generator>
	<entry>
		<id>https://kontenbelajar.com/wiki/index.php?title=Data-cleaning-fisip&amp;diff=406&amp;oldid=prev</id>
		<title>Aditya: Created page with &quot;Ada dua bentuk data mentah:  1. `JSON` → salinan respons API, sedekat mungkin dengan data asli dari Bluesky. 2. `CSV` → field penting sudah dijadikan tabel, tetapi **belum...&quot;</title>
		<link rel="alternate" type="text/html" href="https://kontenbelajar.com/wiki/index.php?title=Data-cleaning-fisip&amp;diff=406&amp;oldid=prev"/>
		<updated>2026-09-16T05:06:27Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;Ada dua bentuk data mentah:  1. `JSON` → salinan respons API, sedekat mungkin dengan data asli dari Bluesky. 2. `CSV` → field penting sudah dijadikan tabel, tetapi **belum...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Ada dua bentuk data mentah:&lt;br /&gt;
&lt;br /&gt;
1. `JSON` → salinan respons API, sedekat mungkin dengan data asli dari Bluesky.&lt;br /&gt;
2. `CSV` → field penting sudah dijadikan tabel, tetapi **belum dibersihkan** sehingga cocok untuk latihan mahasiswa.&lt;br /&gt;
&lt;br /&gt;
Secara resmi, `app.bsky.feed.searchPosts` mewajibkan parameter `q`, mendukung `sort=latest/top`, filter `lang`, dan `limit` maksimum **100** per request. Dokumentasi juga mengingatkan bahwa sintaks pencarian frasa/Boolean tidak sepenuhnya dispesifikasikan, walaupun sintaks Lucene direkomendasikan. &lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# A. Target akhir praktikum&lt;br /&gt;
&lt;br /&gt;
Kita akan menghasilkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
BigDataFisip/&lt;br /&gt;
│&lt;br /&gt;
├── venvs/&lt;br /&gt;
│   └── jupyter-polsci/&lt;br /&gt;
│&lt;br /&gt;
└── data/&lt;br /&gt;
    ├── raw/&lt;br /&gt;
    │   ├── bluesky_climate_change_raw.json&lt;br /&gt;
    │   └── bluesky_climate_change_raw.csv&lt;br /&gt;
    │&lt;br /&gt;
    └── processed/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Mahasiswa nantinya **tidak mengubah file di `raw/`**.&lt;br /&gt;
&lt;br /&gt;
Hasil cleaning disimpan ke:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
data/processed/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# B. Langkah 1 — Pastikan Jupyter menggunakan environment yang benar&lt;br /&gt;
&lt;br /&gt;
Buat cell:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
import sys&lt;br /&gt;
&lt;br /&gt;
print(sys.executable)&lt;br /&gt;
print(sys.version)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pada komputer seharusnya kurang lebih:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/venvs/jupyter-polsci/bin/python&lt;br /&gt;
&lt;br /&gt;
3.10.12 ...&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kalau demikian, environment sudah benar.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# C. Langkah 2 — Import library&lt;br /&gt;
&lt;br /&gt;
Buat cell baru:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
import json&lt;br /&gt;
import requests&lt;br /&gt;
import pandas as pd&lt;br /&gt;
&lt;br /&gt;
from pathlib import Path&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kita menggunakan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
requests  → mengambil data API&lt;br /&gt;
json      → menyimpan respons asli&lt;br /&gt;
pandas    → mengubah data menjadi tabel&lt;br /&gt;
Path      → mengatur folder/file&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# D. Langkah 3 — Tentukan folder penyimpanan&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
PROJECT = Path(&lt;br /&gt;
    &amp;quot;/media/bgoode/Data4/Unpad/Kuliah/BigDataFisip&amp;quot;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
RAW_DIR = PROJECT / &amp;quot;data&amp;quot; / &amp;quot;raw&amp;quot;&lt;br /&gt;
PROCESSED_DIR = PROJECT / &amp;quot;data&amp;quot; / &amp;quot;processed&amp;quot;&lt;br /&gt;
&lt;br /&gt;
RAW_DIR.mkdir(&lt;br /&gt;
    parents=True,&lt;br /&gt;
    exist_ok=True&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
PROCESSED_DIR.mkdir(&lt;br /&gt;
    parents=True,&lt;br /&gt;
    exist_ok=True&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
print(RAW_DIR)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/data/raw&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# E. Langkah 4 — Tentukan topik (misalnya Climate Change)&lt;br /&gt;
&lt;br /&gt;
Endpoint:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
url = &amp;quot;https://api.bsky.app/xrpc/app.bsky.feed.searchPosts&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian query:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
params = {&lt;br /&gt;
    &amp;quot;q&amp;quot;: '&amp;quot;climate change&amp;quot;',&lt;br /&gt;
    &amp;quot;limit&amp;quot;: 100,&lt;br /&gt;
    &amp;quot;sort&amp;quot;: &amp;quot;latest&amp;quot;,&lt;br /&gt;
    &amp;quot;lang&amp;quot;: &amp;quot;en&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Artinya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
q&lt;br /&gt;
↓&lt;br /&gt;
mencari &amp;quot;climate change&amp;quot;&lt;br /&gt;
&lt;br /&gt;
limit&lt;br /&gt;
↓&lt;br /&gt;
maksimal 100 posting&lt;br /&gt;
&lt;br /&gt;
sort&lt;br /&gt;
↓&lt;br /&gt;
latest = hasil terbaru&lt;br /&gt;
&lt;br /&gt;
lang&lt;br /&gt;
↓&lt;br /&gt;
en = bahasa Inggris&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Nilai `100` adalah batas maksimum `limit` menurut Lexicon resmi Bluesky. &lt;br /&gt;
&lt;br /&gt;
Catatan:&lt;br /&gt;
&lt;br /&gt;
&amp;gt; `limit=100` berarti **meminta maksimal 100**, bukan jaminan server selalu memberikan tepat 100.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# F. Langkah 5 — Kirim request&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
response = requests.get(&lt;br /&gt;
    url,&lt;br /&gt;
    params=params,&lt;br /&gt;
    headers={&lt;br /&gt;
        &amp;quot;Accept&amp;quot;: &amp;quot;application/json&amp;quot;,&lt;br /&gt;
        &amp;quot;User-Agent&amp;quot;: &amp;quot;BigDataFisip-Class/1.0&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    timeout=30&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
print(&lt;br /&gt;
    &amp;quot;HTTP Status:&amp;quot;,&lt;br /&gt;
    response.status_code&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
print(&lt;br /&gt;
    &amp;quot;Content-Type:&amp;quot;,&lt;br /&gt;
    response.headers.get(&amp;quot;content-type&amp;quot;)&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Harapannya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
HTTP Status: 200&lt;br /&gt;
Content-Type: application/json; charset=utf-8&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# G. Langkah 6 — Cek hasil JSON&lt;br /&gt;
&lt;br /&gt;
Gunakan:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
if response.status_code != 200:&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;Request gagal&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    print(&lt;br /&gt;
        response.text[:1000]&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
    raise RuntimeError(&lt;br /&gt;
        &amp;quot;Data belum berhasil diambil&amp;quot;&lt;br /&gt;
    )&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian pastikan hasil memang JSON:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
content_type = response.headers.get(&lt;br /&gt;
    &amp;quot;content-type&amp;quot;,&lt;br /&gt;
    &amp;quot;&amp;quot;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
if &amp;quot;application/json&amp;quot; not in content_type:&lt;br /&gt;
&lt;br /&gt;
    raise RuntimeError(&lt;br /&gt;
        &amp;quot;Respons server bukan JSON&amp;quot;&lt;br /&gt;
    )&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Baru setelah itu:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
data = response.json()&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Ini mencegah error:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
JSONDecodeError&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
ketika server sebenarnya memberikan HTML error.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# H. Langkah 7 — Ambil daftar posting&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
posts = data.get(&lt;br /&gt;
    &amp;quot;posts&amp;quot;,&lt;br /&gt;
    []&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
print(&lt;br /&gt;
    &amp;quot;Jumlah posting:&amp;quot;,&lt;br /&gt;
    len(posts)&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Target:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Jumlah posting: 100&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika hasilnya misalnya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Jumlah posting: 86&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
jangan mengubahnya menjadi 100, biarkan saja.&lt;br /&gt;
&lt;br /&gt;
Itu berarti API memang hanya mengembalikan 86 pada request tersebut.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# I. Langkah 8 — Lihat bentuk JSON&lt;br /&gt;
&lt;br /&gt;
Sekarang:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
print(&lt;br /&gt;
    data.keys()&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Lalu:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
print(&lt;br /&gt;
    posts[0].keys()&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Dan lihat posting pertama:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
posts[0]&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Mahasiswa kemungkinan akan melihat struktur yang cukup kompleks.&lt;br /&gt;
&lt;br /&gt;
Secara sederhana:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
post&lt;br /&gt;
│&lt;br /&gt;
├── uri&lt;br /&gt;
├── cid&lt;br /&gt;
│&lt;br /&gt;
├── author&lt;br /&gt;
│   ├── handle&lt;br /&gt;
│   ├── displayName&lt;br /&gt;
│   └── ...&lt;br /&gt;
│&lt;br /&gt;
├── record&lt;br /&gt;
│   ├── text&lt;br /&gt;
│   ├── createdAt&lt;br /&gt;
│   ├── langs&lt;br /&gt;
│   └── ...&lt;br /&gt;
│&lt;br /&gt;
├── replyCount&lt;br /&gt;
├── repostCount&lt;br /&gt;
├── likeCount&lt;br /&gt;
└── ...&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
&amp;gt; **Data dari API belum tentu berbentuk tabel seperti Excel.**&lt;br /&gt;
&lt;br /&gt;
Data API sering berbentuk:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
JSON&lt;br /&gt;
    ↓&lt;br /&gt;
nested / bertingkat&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# J. Langkah 9 — Simpan JSON mentah terlebih dahulu&lt;br /&gt;
&lt;br /&gt;
**Lakukan ini sebelum cleaning.**&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
json_file = (&lt;br /&gt;
    RAW_DIR /&lt;br /&gt;
    &amp;quot;bluesky_climate_change_raw.json&amp;quot;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
with open(&lt;br /&gt;
    json_file,&lt;br /&gt;
    &amp;quot;w&amp;quot;,&lt;br /&gt;
    encoding=&amp;quot;utf-8&amp;quot;&lt;br /&gt;
) as f:&lt;br /&gt;
&lt;br /&gt;
    json.dump(&lt;br /&gt;
        data,&lt;br /&gt;
        f,&lt;br /&gt;
        ensure_ascii=False,&lt;br /&gt;
        indent=2&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
print(&lt;br /&gt;
    &amp;quot;Tersimpan:&amp;quot;,&lt;br /&gt;
    json_file&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Sekarang kita memiliki:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
data/raw/&lt;br /&gt;
└── bluesky_climate_change_raw.json&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
File ini **jangan diedit**.&lt;br /&gt;
&lt;br /&gt;
Anggap sebagai:&lt;br /&gt;
&lt;br /&gt;
&amp;gt; salinan data asli yang diterima dari API.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# K. Langkah 10 — Pilih field yang akan dipelajari mahasiswa&lt;br /&gt;
&lt;br /&gt;
Sekarang JSON bertingkat kita ubah menjadi tabel.&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
rows = []&lt;br /&gt;
&lt;br /&gt;
for post in posts:&lt;br /&gt;
&lt;br /&gt;
    record = post.get(&lt;br /&gt;
        &amp;quot;record&amp;quot;,&lt;br /&gt;
        {}&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
    author = post.get(&lt;br /&gt;
        &amp;quot;author&amp;quot;,&lt;br /&gt;
        {}&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
    rows.append({&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;uri&amp;quot;:&lt;br /&gt;
            post.get(&amp;quot;uri&amp;quot;),&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;created_at&amp;quot;:&lt;br /&gt;
            record.get(&amp;quot;createdAt&amp;quot;),&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;username&amp;quot;:&lt;br /&gt;
            author.get(&amp;quot;handle&amp;quot;),&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;display_name&amp;quot;:&lt;br /&gt;
            author.get(&amp;quot;displayName&amp;quot;),&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;text&amp;quot;:&lt;br /&gt;
            record.get(&amp;quot;text&amp;quot;),&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;language&amp;quot;:&lt;br /&gt;
            record.get(&amp;quot;langs&amp;quot;),&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;reply_count&amp;quot;:&lt;br /&gt;
            post.get(&lt;br /&gt;
                &amp;quot;replyCount&amp;quot;,&lt;br /&gt;
                0&lt;br /&gt;
            ),&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;repost_count&amp;quot;:&lt;br /&gt;
            post.get(&lt;br /&gt;
                &amp;quot;repostCount&amp;quot;,&lt;br /&gt;
                0&lt;br /&gt;
            ),&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;like_count&amp;quot;:&lt;br /&gt;
            post.get(&lt;br /&gt;
                &amp;quot;likeCount&amp;quot;,&lt;br /&gt;
                0&lt;br /&gt;
            )&lt;br /&gt;
    })&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
df_raw = pd.DataFrame(&lt;br /&gt;
    rows&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# L. Langkah 11 — Lihat hasil tabel&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
df_raw.head()&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kurang lebih mahasiswa akan memperoleh:&lt;br /&gt;
&lt;br /&gt;
| created_at | username | text              | language | reply_count | repost_count | like_count |&lt;br /&gt;
| ---------- | -------- | ----------------- | -------- | ----------: | -----------: | ---------: |&lt;br /&gt;
| ...        | user1    | Climate change... | ['en']   |           1 |            3 |         12 |&lt;br /&gt;
| ...        | user2    | New report...     | ['en']   |           0 |            1 |          6 |&lt;br /&gt;
| ...        | user3    | ...               | ['en']   |           2 |            0 |          9 |&lt;br /&gt;
&lt;br /&gt;
Kemudian:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
df_raw.shape&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Harapannya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
(100, 9)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# M. Langkah 12 — Periksa kondisi data, tetapi jangan dibersihkan dahulu&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
df_raw.info()&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
df_raw.isna().sum()&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Cek juga:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
df_raw.head(10)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Dan:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
df_raw[&amp;quot;text&amp;quot;].head(10)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pada tahap ini mahasiswa hanya **mengamati**.&lt;br /&gt;
&lt;br /&gt;
Belum:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
dropna()&lt;br /&gt;
drop_duplicates()&lt;br /&gt;
replace()&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
dan sebagainya.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# N. Langkah 13 — Simpan CSV mentah&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
csv_file = (&lt;br /&gt;
    RAW_DIR /&lt;br /&gt;
    &amp;quot;bluesky_climate_change_raw.csv&amp;quot;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
df_raw.to_csv(&lt;br /&gt;
    csv_file,&lt;br /&gt;
    index=False,&lt;br /&gt;
    encoding=&amp;quot;utf-8-sig&amp;quot;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
print(&lt;br /&gt;
    &amp;quot;Tersimpan:&amp;quot;,&lt;br /&gt;
    csv_file&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil akhirnya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
BigDataFisip/&lt;br /&gt;
└── data/&lt;br /&gt;
    │&lt;br /&gt;
    ├── raw/&lt;br /&gt;
    │   ├── bluesky_climate_change_raw.json&lt;br /&gt;
    │   └── bluesky_climate_change_raw.csv&lt;br /&gt;
    │&lt;br /&gt;
    └── processed/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Saya menggunakan:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
encoding=&amp;quot;utf-8-sig&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
supaya karakter seperti emoji dan karakter non-ASCII relatif aman jika CSV nantinya dibuka menggunakan Excel.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# O. Perbedaan dua file tersebut&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### `raw.json`&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Bluesky API&lt;br /&gt;
     ↓&lt;br /&gt;
  JSON asli&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Belum kita ubah strukturnya.&lt;br /&gt;
&lt;br /&gt;
### `raw.csv`&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
JSON&lt;br /&gt;
 ↓&lt;br /&gt;
pilih field&lt;br /&gt;
 ↓&lt;br /&gt;
tabel&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Sudah mengalami **transformasi struktur**, tetapi belum mengalami cleaning isi.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# P. Sekarang mahasiswa mendapatkan dataset untuk cleaning&lt;br /&gt;
&lt;br /&gt;
Setelah raw CSV tersedia, praktik berikutnya bisa dimulai.&lt;br /&gt;
&lt;br /&gt;
### 1. Cek tipe data&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
df_raw.info()&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
### 2. Cari missing value&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
df_raw.isna().sum()&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Mahasiswa menentukan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
mana yang kosong?&lt;br /&gt;
kenapa bisa kosong?&lt;br /&gt;
perlukah dihapus?&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
### 3. Periksa duplikasi&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
df_raw.duplicated().sum()&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Lebih baik juga:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
df_raw.duplicated(&lt;br /&gt;
    subset=[&amp;quot;uri&amp;quot;]&lt;br /&gt;
).sum()&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Diskusikan:&lt;br /&gt;
&lt;br /&gt;
&amp;gt; Mengapa `uri` lebih cocok untuk memeriksa posting yang sama dibandingkan seluruh row?&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
### 4. Periksa teks&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
display(&lt;br /&gt;
    df_raw[[&amp;quot;text&amp;quot;]]&lt;br /&gt;
    .head(20)&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemungkinan ditemukan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
URL&lt;br /&gt;
emoji&lt;br /&gt;
hashtag&lt;br /&gt;
newline&lt;br /&gt;
spasi berlebih&lt;br /&gt;
mention&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Itulah bahan untuk text cleaning.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
### 5. Periksa relevansi&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Cari:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
df_raw[&lt;br /&gt;
    [&amp;quot;text&amp;quot;]&lt;br /&gt;
].head(20)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Tanyakan:&lt;br /&gt;
&lt;br /&gt;
&amp;gt; Apakah semuanya benar-benar membahas climate change?&lt;br /&gt;
&lt;br /&gt;
Tidak boleh otomatis diasumsikan iya, karena dokumentasi Bluesky sendiri menyatakan sintaks dan perilaku query tidak sepenuhnya dispesifikasikan. &lt;br /&gt;
&lt;br /&gt;
Ini bisa menjadi contoh nyata:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Search API&lt;br /&gt;
     ↓&lt;br /&gt;
candidate data&lt;br /&gt;
&lt;br /&gt;
bukan&lt;br /&gt;
&lt;br /&gt;
Search API&lt;br /&gt;
     ↓&lt;br /&gt;
ground truth&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# Q. Tugas cleaning &lt;br /&gt;
&lt;br /&gt;
Mahasiswa diminta menghasilkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
bluesky_climate_change_clean.csv&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
dari:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
bluesky_climate_change_raw.csv&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Dengan tugas:&lt;br /&gt;
&lt;br /&gt;
**1. Konversi tanggal**&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
created_at&lt;br /&gt;
string → datetime&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**2. Missing value**&lt;br /&gt;
&lt;br /&gt;
Identifikasi dan tentukan perlakuannya.&lt;br /&gt;
&lt;br /&gt;
**3. Duplikasi**&lt;br /&gt;
&lt;br /&gt;
Gunakan `uri` untuk membantu mendeteksi posting yang sama.&lt;br /&gt;
&lt;br /&gt;
**4. Cleaning text**&lt;br /&gt;
&lt;br /&gt;
Misalnya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
newline&lt;br /&gt;
spasi berlebih&lt;br /&gt;
URL&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Namun mahasiswa harus menjelaskan **mengapa suatu elemen dihapus**, bukan sekadar menghapus semuanya.&lt;br /&gt;
&lt;br /&gt;
**5. Relevansi topik**&lt;br /&gt;
&lt;br /&gt;
Periksa apakah posting benar-benar terkait perubahan iklim.&lt;br /&gt;
&lt;br /&gt;
**6. Engagement**&lt;br /&gt;
&lt;br /&gt;
Buat variabel:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
engagement&lt;br /&gt;
=&lt;br /&gt;
reply_count&lt;br /&gt;
+&lt;br /&gt;
repost_count&lt;br /&gt;
+&lt;br /&gt;
like_count&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# R. Kode lengkap pengambilan data&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
import json&lt;br /&gt;
import requests&lt;br /&gt;
import pandas as pd&lt;br /&gt;
&lt;br /&gt;
from pathlib import Path&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ========================================&lt;br /&gt;
# 1. Folder project&lt;br /&gt;
# ========================================&lt;br /&gt;
&lt;br /&gt;
PROJECT = Path(&lt;br /&gt;
    &amp;quot;/media/bgoode/Data4/Unpad/Kuliah/BigDataFisip&amp;quot;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
RAW_DIR = PROJECT / &amp;quot;data&amp;quot; / &amp;quot;raw&amp;quot;&lt;br /&gt;
&lt;br /&gt;
RAW_DIR.mkdir(&lt;br /&gt;
    parents=True,&lt;br /&gt;
    exist_ok=True&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ========================================&lt;br /&gt;
# 2. API&lt;br /&gt;
# ========================================&lt;br /&gt;
&lt;br /&gt;
url = (&lt;br /&gt;
    &amp;quot;https://api.bsky.app/&amp;quot;&lt;br /&gt;
    &amp;quot;xrpc/app.bsky.feed.searchPosts&amp;quot;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
params = {&lt;br /&gt;
    &amp;quot;q&amp;quot;: '&amp;quot;climate change&amp;quot;',&lt;br /&gt;
    &amp;quot;limit&amp;quot;: 100,&lt;br /&gt;
    &amp;quot;sort&amp;quot;: &amp;quot;latest&amp;quot;,&lt;br /&gt;
    &amp;quot;lang&amp;quot;: &amp;quot;en&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ========================================&lt;br /&gt;
# 3. Request&lt;br /&gt;
# ========================================&lt;br /&gt;
&lt;br /&gt;
response = requests.get(&lt;br /&gt;
    url,&lt;br /&gt;
    params=params,&lt;br /&gt;
    headers={&lt;br /&gt;
        &amp;quot;Accept&amp;quot;:&lt;br /&gt;
            &amp;quot;application/json&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;User-Agent&amp;quot;:&lt;br /&gt;
            &amp;quot;BigDataFisip-Class/1.0&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    timeout=30&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print(&lt;br /&gt;
    &amp;quot;HTTP Status:&amp;quot;,&lt;br /&gt;
    response.status_code&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ========================================&lt;br /&gt;
# 4. Validasi response&lt;br /&gt;
# ========================================&lt;br /&gt;
&lt;br /&gt;
if response.status_code != 200:&lt;br /&gt;
&lt;br /&gt;
    raise RuntimeError(&lt;br /&gt;
        f&amp;quot;HTTP {response.status_code}: &amp;quot;&lt;br /&gt;
        f&amp;quot;{response.text[:300]}&amp;quot;&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data = response.json()&lt;br /&gt;
&lt;br /&gt;
posts = data.get(&lt;br /&gt;
    &amp;quot;posts&amp;quot;,&lt;br /&gt;
    []&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
print(&lt;br /&gt;
    &amp;quot;Jumlah posting:&amp;quot;,&lt;br /&gt;
    len(posts)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ========================================&lt;br /&gt;
# 5. Simpan JSON asli&lt;br /&gt;
# ========================================&lt;br /&gt;
&lt;br /&gt;
json_file = (&lt;br /&gt;
    RAW_DIR /&lt;br /&gt;
    &amp;quot;bluesky_climate_change_raw.json&amp;quot;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
with open(&lt;br /&gt;
    json_file,&lt;br /&gt;
    &amp;quot;w&amp;quot;,&lt;br /&gt;
    encoding=&amp;quot;utf-8&amp;quot;&lt;br /&gt;
) as f:&lt;br /&gt;
&lt;br /&gt;
    json.dump(&lt;br /&gt;
        data,&lt;br /&gt;
        f,&lt;br /&gt;
        ensure_ascii=False,&lt;br /&gt;
        indent=2&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ========================================&lt;br /&gt;
# 6. Ubah ke tabel&lt;br /&gt;
# ========================================&lt;br /&gt;
&lt;br /&gt;
rows = []&lt;br /&gt;
&lt;br /&gt;
for post in posts:&lt;br /&gt;
&lt;br /&gt;
    record = post.get(&lt;br /&gt;
        &amp;quot;record&amp;quot;,&lt;br /&gt;
        {}&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
    author = post.get(&lt;br /&gt;
        &amp;quot;author&amp;quot;,&lt;br /&gt;
        {}&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
    rows.append({&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;uri&amp;quot;:&lt;br /&gt;
            post.get(&amp;quot;uri&amp;quot;),&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;created_at&amp;quot;:&lt;br /&gt;
            record.get(&amp;quot;createdAt&amp;quot;),&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;username&amp;quot;:&lt;br /&gt;
            author.get(&amp;quot;handle&amp;quot;),&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;display_name&amp;quot;:&lt;br /&gt;
            author.get(&amp;quot;displayName&amp;quot;),&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;text&amp;quot;:&lt;br /&gt;
            record.get(&amp;quot;text&amp;quot;),&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;language&amp;quot;:&lt;br /&gt;
            record.get(&amp;quot;langs&amp;quot;),&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;reply_count&amp;quot;:&lt;br /&gt;
            post.get(&lt;br /&gt;
                &amp;quot;replyCount&amp;quot;,&lt;br /&gt;
                0&lt;br /&gt;
            ),&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;repost_count&amp;quot;:&lt;br /&gt;
            post.get(&lt;br /&gt;
                &amp;quot;repostCount&amp;quot;,&lt;br /&gt;
                0&lt;br /&gt;
            ),&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;like_count&amp;quot;:&lt;br /&gt;
            post.get(&lt;br /&gt;
                &amp;quot;likeCount&amp;quot;,&lt;br /&gt;
                0&lt;br /&gt;
            )&lt;br /&gt;
    })&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
df_raw = pd.DataFrame(&lt;br /&gt;
    rows&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ========================================&lt;br /&gt;
# 7. Simpan CSV raw&lt;br /&gt;
# ========================================&lt;br /&gt;
&lt;br /&gt;
csv_file = (&lt;br /&gt;
    RAW_DIR /&lt;br /&gt;
    &amp;quot;bluesky_climate_change_raw.csv&amp;quot;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
df_raw.to_csv(&lt;br /&gt;
    csv_file,&lt;br /&gt;
    index=False,&lt;br /&gt;
    encoding=&amp;quot;utf-8-sig&amp;quot;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ========================================&lt;br /&gt;
# 8. Pemeriksaan&lt;br /&gt;
# ========================================&lt;br /&gt;
&lt;br /&gt;
print(&lt;br /&gt;
    &amp;quot;Ukuran dataset:&amp;quot;,&lt;br /&gt;
    df_raw.shape&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
display(&lt;br /&gt;
    df_raw.head()&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
100 data mentah&lt;br /&gt;
       ↓&lt;br /&gt;
identifikasi masalah&lt;br /&gt;
       ↓&lt;br /&gt;
data cleaning&lt;br /&gt;
       ↓&lt;br /&gt;
data processed&lt;br /&gt;
       ↓&lt;br /&gt;
analisis&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
[1]: https://bsky.network/docs/api-directory/?utm_source=chatgpt.com &amp;quot;API Hosts and Auth | Bluesky Protocol Services&amp;quot;&lt;/div&gt;</summary>
		<author><name>Aditya</name></author>
		
	</entry>
</feed>