Day 2 Algorit.ma : Data Wrangling and Visualization
Day 2, here I will share my notes of Inclass notebook. For further example you can check out on https://github.com/Saltfarmer/Algoritma-BFLP-DS-Audit/tree/main
Inclass: Data Wrangling and Visualization
This notebook was made based on main materials Data Wrangling and Visualization.ipynb
Version: BRI Audit Analytics - January 2024
Training Objectives
- Reproducible Environment
- Working with Multi-Index DataFrames
- Subsetting Multi-Index DataFrames
- Visual Data Exploratory
- Using Group By Effectively
Reproducible Environment
Ada beberapa paket baru yang akan digunakan dalam materi ini. Biasanya, kita dapat menggunakan pip install
/conda install
untuk menginstal library baru ke environment kita. Namun untuk saat ini, mari kita coba pendekatan lain dalam mempersiapkan library yang diperlukan untuk proyek tertentu.
Bayangkan Anda sedang bekerja dengan tim Anda dalam sebuah proyek kolaboratif. Anda menginisialisasi proyek dengan dependensi dan versi tertentu di komputer Anda dan semuanya berjalan dengan baik. Nantinya, Anda perlu ‘mengirimkan’ proyek itu ke tim Anda yang mengharuskan mereka menyiapkan environment yang sama dengan Anda. Lalu apa yang akan Anda lakukan untuk memastikan program itu juga berjalan lancar di mesin mereka?
Di sinilah Anda perlu membuat environment Anda dapat direproduksi dengan membuat file requirements.txt
.
Lihat pada folder material utama, Anda akan menemukan file requirements.txt
yang isinya seperti ini:
matplotlib==3.8.1
numpy==1.26.1
pandas==2.0.0
yfinance==0.2.31
Perhatikan kita memiliki baris untuk setiap library, lalu nomor versi. Hal ini penting karena saat Anda mulai mengembangkan aplikasi python, Anda akan mengembangkan aplikasi dengan mempertimbangkan versi library tertentu. Sederhananya, requirements.txt
membantu melacak versi setiap library yang Anda gunakan untuk mencegah perubahan yang tidak terduga.
Importing Requirements
Kita sudah membahas untuk apa file persyaratan itu, tetapi bagaimana cara menggunakannya? Karena kita tidak ingin menginstal dan melacak secara manual setiap library yang diperlukan untuk proyek tertentu, mari kita coba mengimpor persyaratan dengan langkah-langkah berikut:
-
Aktifkan environment yang ingin digunakan:
conda activate <ENV_NAME>
Apabila belum ada, maka perlu membuat environment baru:
conda create -n [ENV_NAME] python=[PYTHON_VERSION]
Jangan lupa instalasi kernel di dalam environment tersebut apabila ingin dapat diakses menggunakan jupyter notebook:
> pip install ipykernel
> python -m ipykernel install --user --name=[ENV_NAME]
-
Navigasikan path ke folder di mana file
requirements.txt
beradacd <PATH_TO_REQUIREMENTS>
-
Instalasi packages dari file tersebut
pip install -r requirements.txt
Exporting Requirements
Perintah pip install
selalu menginstal versi terbaru dari sebuah library, namun terkadang, Anda mungkin ingin menginstal versi tertentu yang Anda tahu berfungsi pada proyek Anda.
File persyaratan memungkinkan Anda menentukan dengan tepat library dan versi mana yang harus diinstal. Anda dapat mengikuti langkah-langkah berikut untuk membuat file kebutuhan Anda:
- Aktifkan environment
conda activate <ENV_NAME>
- Navigasikan path ke folder tempat di mana file
requirements.txt
ingin disimpan
cd <PATH_TO_REQUIREMENTS_FOLDER>
- Export environment: membuat daftar packages beserta versinya.
pip list --format=freeze > requirements.txt
Anda dapat menyimpan file dengan nama lain, namun sebagai konvensi biasa digunakan penamaan requirements.txt
Data Wrangling dan Reshaping
Pada materi sebelumnya, kita sudah mempelajari beberapa teknik yang biasa digunakan untuk eksplorasi data pada pandas
. Secara spesifik, pada materi P4DA, berbagai tools yang digunakan untuk inspeksi, diagnostic, dan exploratory yaitu:
Data Inspection
.head()
and.tail()
.describe()
.dtypes
- Subsetting using
.loc
,.iloc
and conditionals
Load Data
yfinance
Kita akan menggunakan library yfinance
untuk mengakses data saham yang tersedia pada Yahoo! Finance. Penarikan data menggunakan yfinance
membutuhkan koneksi internet.
Dokumentasi: https://pypi.org/project/yfinance/
import pandas as pd
import yfinance as data
from datetime import date
# Formatting output ke bentuk 2 desimal
pd.set_option('display.float_format', lambda x: '%.2f' % x)
symbol = ['BRIS.JK' ,'BBRI.JK', 'BMRI.JK']
start_date = '2020-01-01' # 1 Januari 2020
end_date = date.today() # 4 Januari 2024 hari ini
stock = data.download(tickers = symbol, start = start_date, end = end_date)
stock.columns.names = ['Attributes', 'Symbols']
stock.head()
[*********************100%%**********************] 3 of 3 completed
Attributes | Adj Close | Close | High | Low | Open | Volume | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Symbols | BBRI.JK | BMRI.JK | BRIS.JK | BBRI.JK | BMRI.JK | BRIS.JK | BBRI.JK | BMRI.JK | BRIS.JK | BBRI.JK | BMRI.JK | BRIS.JK | BBRI.JK | BMRI.JK | BRIS.JK | BBRI.JK | BMRI.JK | BRIS.JK |
Date | ||||||||||||||||||
2020-01-02 | 3717.37 | 3239.33 | 326.18 | 4410.00 | 3875.00 | 332.00 | 4410.00 | 3887.50 | 336.00 | 4360.00 | 3825.00 | 330.00 | 4400.00 | 3837.50 | 330.00 | 41714100 | 37379800 | 1456400 |
2020-01-03 | 3725.80 | 3228.88 | 322.25 | 4420.00 | 3862.50 | 328.00 | 4440.00 | 3912.50 | 336.00 | 4390.00 | 3812.50 | 326.00 | 4420.00 | 3875.00 | 334.00 | 82898300 | 70294600 | 4989600 |
2020-01-06 | 3683.65 | 3176.63 | 318.32 | 4370.00 | 3800.00 | 324.00 | 4390.00 | 3837.50 | 334.00 | 4320.00 | 3762.50 | 320.00 | 4360.00 | 3825.00 | 328.00 | 44225100 | 61892000 | 6937900 |
2020-01-07 | 3708.94 | 3176.63 | 312.42 | 4400.00 | 3800.00 | 318.00 | 4410.00 | 3862.50 | 324.00 | 4380.00 | 3787.50 | 316.00 | 4410.00 | 3862.50 | 324.00 | 103948100 | 70895600 | 6319400 |
2020-01-08 | 3692.08 | 3134.83 | 306.53 | 4380.00 | 3750.00 | 312.00 | 4400.00 | 3775.00 | 318.00 | 4340.00 | 3687.50 | 312.00 | 4380.00 | 3775.00 | 318.00 | 171751200 | 105080600 | 4058800 |
stock.tail()
Attributes | Adj Close | Close | High | Low | Open | Volume | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Symbols | BBRI.JK | BMRI.JK | BRIS.JK | BBRI.JK | BMRI.JK | BRIS.JK | BBRI.JK | BMRI.JK | BRIS.JK | BBRI.JK | BMRI.JK | BRIS.JK | BBRI.JK | BMRI.JK | BRIS.JK | BBRI.JK | BMRI.JK | BRIS.JK |
Date | ||||||||||||||||||
2023-12-27 | 5542.47 | 6000.00 | 1695.00 | 5625.00 | 6000.00 | 1695.00 | 5725.00 | 6025.00 | 1705.00 | 5625.00 | 5925.00 | 1685.00 | 5700.00 | 6000.00 | 1695.00 | 122236700 | 43114900 | 10923600 |
2023-12-28 | 5641.00 | 6125.00 | 1740.00 | 5725.00 | 6125.00 | 1740.00 | 5750.00 | 6150.00 | 1745.00 | 5675.00 | 6000.00 | 1685.00 | 5700.00 | 6050.00 | 1695.00 | 121434600 | 75118700 | 23222700 |
2023-12-29 | 5641.00 | 6050.00 | 1740.00 | 5725.00 | 6050.00 | 1740.00 | 5750.00 | 6125.00 | 1745.00 | 5675.00 | 6000.00 | 1710.00 | 5750.00 | 6125.00 | 1735.00 | 93126000 | 63097100 | 21099100 |
2024-01-02 | 5675.00 | 6125.00 | 1740.00 | 5675.00 | 6125.00 | 1740.00 | 5675.00 | 6125.00 | 1745.00 | 5625.00 | 6025.00 | 1710.00 | 5650.00 | 6050.00 | 1740.00 | 91143100 | 26235700 | 13118700 |
2024-01-03 | 5600.00 | 6100.00 | 1800.00 | 5600.00 | 6100.00 | 1800.00 | 5650.00 | 6150.00 | 1830.00 | 5600.00 | 6050.00 | 1730.00 | 5625.00 | 6100.00 | 1735.00 | 83659700 | 30053900 | 76511200 |
BRIS.JK
: PT Bank Syariah Indonesia (Persero) TbkBBRI.JK
: PT Bank Rakyat Indonesia (Persero) TbkBMRI.JK
: PT Bank Mandiri (Persero) Tbk
Date
- tanggal dalam formatyyyy-mm-dd
High
- nilai saham tertinggi pada hari tersebutLow
- nilai saham terendah pada hari tersebutOpen
- nilai saham saat trading hours dibuka pada hari tersebutClose
- nilai saham saat trading hours ditutup pada hari tersebutAdj Close
- nilaiClose
yang telah disesuaikan setelah stock split maupun pembagian dividenVolume
- jumlah lembar saham yang ditransaksikan pada hari tersebut
Trading hours dapat berbeda-beda pada tiap tempat. Di Indonesia (IDX/BEI), trading hours dibuka pada Senin - Jumat jam 09:00 WIB - 04:00 WIB.
Untuk membuat analisis kedepannya lebih mudah, kita akan melakukan rename kolom pada Symbols
stock = stock.rename(columns = {'BRIS.JK' : 'BRIS',
'BBRI.JK': 'BBRI',
'BMRI.JK' : 'BMRI'})
stock.head(2)
Attributes | Adj Close | Close | High | Low | Open | Volume | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Symbols | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS |
Date | ||||||||||||||||||
2020-01-02 | 3717.37 | 3239.33 | 326.18 | 4410.00 | 3875.00 | 332.00 | 4410.00 | 3887.50 | 336.00 | 4360.00 | 3825.00 | 330.00 | 4400.00 | 3837.50 | 330.00 | 41714100 | 37379800 | 1456400 |
2020-01-03 | 3725.80 | 3228.88 | 322.25 | 4420.00 | 3862.50 | 328.00 | 4440.00 | 3912.50 | 336.00 | 4390.00 | 3812.50 | 326.00 | 4420.00 | 3875.00 | 334.00 | 82898300 | 70294600 | 4989600 |
Slicing Multi-Index DataFrame
Multi-Index Dataframe adalah bentuk dataframe yang memiliki level indexing lebih dari 1 baik pada baris, kolom, ataupun keduanya. Hal yang perlu diperhatikan dalam MultiIndex Dataframe adalah bentuk dataframe ini terkadang tidak bisa langsung kita gunakan untuk menganalisis data, sehingga akan ada beberapa perlakuan untuk kita mengiris atau mengubah bentuknya ke dataframe yang lebih sederhana. Berikut contoh bentuk multi-index dataframe:
Perhatikan bahwa data stock
adalah Multi-Index DataFrame, di mana level dari columnnya terdiri dari:
Attributes
= level 0Symbols
= level 1
stock.head()
Attributes | Adj Close | Close | High | Low | Open | Volume | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Symbols | BBRI.JK | BMRI.JK | BRIS.JK | BBRI.JK | BMRI.JK | BRIS.JK | BBRI.JK | BMRI.JK | BRIS.JK | BBRI.JK | BMRI.JK | BRIS.JK | BBRI.JK | BMRI.JK | BRIS.JK | BBRI.JK | BMRI.JK | BRIS.JK |
Date | ||||||||||||||||||
2020-01-02 | 3717.37 | 3239.33 | 326.18 | 4410.00 | 3875.00 | 332.00 | 4410.00 | 3887.50 | 336.00 | 4360.00 | 3825.00 | 330.00 | 4400.00 | 3837.50 | 330.00 | 41714100 | 37379800 | 1456400 |
2020-01-03 | 3725.80 | 3228.88 | 322.25 | 4420.00 | 3862.50 | 328.00 | 4440.00 | 3912.50 | 336.00 | 4390.00 | 3812.50 | 326.00 | 4420.00 | 3875.00 | 334.00 | 82898300 | 70294600 | 4989600 |
2020-01-06 | 3683.65 | 3176.63 | 318.32 | 4370.00 | 3800.00 | 324.00 | 4390.00 | 3837.50 | 334.00 | 4320.00 | 3762.50 | 320.00 | 4360.00 | 3825.00 | 328.00 | 44225100 | 61892000 | 6937900 |
2020-01-07 | 3708.94 | 3176.63 | 312.42 | 4400.00 | 3800.00 | 318.00 | 4410.00 | 3862.50 | 324.00 | 4380.00 | 3787.50 | 316.00 | 4410.00 | 3862.50 | 324.00 | 103948100 | 70895600 | 6319400 |
2020-01-08 | 3692.08 | 3134.83 | 306.53 | 4380.00 | 3750.00 | 312.00 | 4400.00 | 3775.00 | 318.00 | 4340.00 | 3687.50 | 312.00 | 4380.00 | 3775.00 | 318.00 | 171751200 | 105080600 | 4058800 |
Ketika kita subset menggunakan
[]
, maka kita hanya bisa mengakses kolom dengan level teratas saja, yaitu untukAttributes
.
❓ Subset pada kolom High
akan menghasilkan DataFrame Single Index dengan Symbols
sebagai levelnya
# Ambil kolom High dengan semua attributnya
stock['High']
Symbols | BBRI | BMRI | BRIS |
---|---|---|---|
Date | |||
2020-01-02 | 4410.00 | 3887.50 | 336.00 |
2020-01-03 | 4440.00 | 3912.50 | 336.00 |
2020-01-06 | 4390.00 | 3837.50 | 334.00 |
2020-01-07 | 4410.00 | 3862.50 | 324.00 |
2020-01-08 | 4400.00 | 3775.00 | 318.00 |
... | ... | ... | ... |
2023-12-27 | 5725.00 | 6025.00 | 1705.00 |
2023-12-28 | 5750.00 | 6150.00 | 1745.00 |
2023-12-29 | 5750.00 | 6125.00 | 1745.00 |
2024-01-02 | 5675.00 | 6125.00 | 1745.00 |
2024-01-03 | 5650.00 | 6150.00 | 1830.00 |
976 rows × 3 columns
❓ Masalah: Bagaimana jika kita ingin mengambil semua nilai Attributes
untuk saham BRIS
?
# Pake cross section
# stock.xs(key='BRIS', level= 1, axis = 1)
# Pake loc dan slice
# stock.loc[:, (slice(None), "BRIS")]
# Pake cara swaplevel terlebih dahulu baru panggil BRIS
stock.swaplevel(axis=1)['BRIS']
Attributes | Adj Close | Close | High | Low | Open | Volume |
---|---|---|---|---|---|---|
Date | ||||||
2020-01-02 | 326.18 | 332.00 | 336.00 | 330.00 | 330.00 | 1456400 |
2020-01-03 | 322.25 | 328.00 | 336.00 | 326.00 | 334.00 | 4989600 |
2020-01-06 | 318.32 | 324.00 | 334.00 | 320.00 | 328.00 | 6937900 |
2020-01-07 | 312.42 | 318.00 | 324.00 | 316.00 | 324.00 | 6319400 |
2020-01-08 | 306.53 | 312.00 | 318.00 | 312.00 | 318.00 | 4058800 |
... | ... | ... | ... | ... | ... | ... |
2023-12-27 | 1695.00 | 1695.00 | 1705.00 | 1685.00 | 1695.00 | 10923600 |
2023-12-28 | 1740.00 | 1740.00 | 1745.00 | 1685.00 | 1695.00 | 23222700 |
2023-12-29 | 1740.00 | 1740.00 | 1745.00 | 1710.00 | 1735.00 | 21099100 |
2024-01-02 | 1740.00 | 1740.00 | 1745.00 | 1710.00 | 1740.00 | 13118700 |
2024-01-03 | 1800.00 | 1800.00 | 1830.00 | 1730.00 | 1735.00 | 76511200 |
976 rows × 6 columns
Cross Section
Menggunakan method .xs()
(cross section) untuk mengambil kolom (axis = 1
) pada level dalam. Parameter:
key
: nama kolom/baris yang kita ingin ambillevel
: kolom/baris tersebut ada di level apa?axis
: levelnya terdapat pada index kolom/baris0
untuk baris1
untuk kolom
stock.head(2)
Attributes | Adj Close | Close | High | Low | Open | Volume | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Symbols | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS |
Date | ||||||||||||||||||
2020-01-02 | 3717.37 | 3239.33 | 326.18 | 4410.00 | 3875.00 | 332.00 | 4410.00 | 3887.50 | 336.00 | 4360.00 | 3825.00 | 330.00 | 4400.00 | 3837.50 | 330.00 | 41714100 | 37379800 | 1456400 |
2020-01-03 | 3725.80 | 3228.88 | 322.25 | 4420.00 | 3862.50 | 328.00 | 4440.00 | 3912.50 | 336.00 | 4390.00 | 3812.50 | 326.00 | 4420.00 | 3875.00 | 334.00 | 82898300 | 70294600 | 4989600 |
# mengambil seluruh nilai BRIS
bris = stock.xs(key='BRIS', level=1, axis=1)
bris
Attributes | Adj Close | Close | High | Low | Open | Volume |
---|---|---|---|---|---|---|
Date | ||||||
2020-01-02 | 326.18 | 332.00 | 336.00 | 330.00 | 330.00 | 1456400 |
2020-01-03 | 322.25 | 328.00 | 336.00 | 326.00 | 334.00 | 4989600 |
2020-01-06 | 318.32 | 324.00 | 334.00 | 320.00 | 328.00 | 6937900 |
2020-01-07 | 312.42 | 318.00 | 324.00 | 316.00 | 324.00 | 6319400 |
2020-01-08 | 306.53 | 312.00 | 318.00 | 312.00 | 318.00 | 4058800 |
... | ... | ... | ... | ... | ... | ... |
2023-12-27 | 1695.00 | 1695.00 | 1705.00 | 1685.00 | 1695.00 | 10923600 |
2023-12-28 | 1740.00 | 1740.00 | 1745.00 | 1685.00 | 1695.00 | 23222700 |
2023-12-29 | 1740.00 | 1740.00 | 1745.00 | 1710.00 | 1735.00 | 21099100 |
2024-01-02 | 1740.00 | 1740.00 | 1745.00 | 1710.00 | 1740.00 | 13118700 |
2024-01-03 | 1800.00 | 1800.00 | 1830.00 | 1730.00 | 1735.00 | 76511200 |
976 rows × 6 columns
✅ Knowledge Check
Coba ambil seluruh nilai saham BBRI pada tanggal 12 Desember 2022!
Hint: Gunakan metode .loc
untuk mengambil tanggal yang bersesuaian
# your code here
stock.loc['2022-12-12' ,(slice(None), "BBRI")]
Attributes Symbols
Adj Close BBRI 4496.79
Close BBRI 4850.00
High BBRI 4850.00
Low BBRI 4760.00
Open BBRI 4800.00
Volume BBRI 139582400.00
Name: 2022-12-12 00:00:00, dtype: float64
[Extra Challenge] Ambil history data harga saham BRIS pada 2 minggu terakhir dari data!
from datetime import datetime, timedelta
# your code here
# stock.iloc[-14: ,:].loc[:, (slice(None), "BRIS")]
# Ngambil dari BRIS variabel
checkpoint = (datetime.now() - timedelta(days=14)).strftime('%Y-%m-%d')
bris.loc[checkpoint:]
Attributes | Adj Close | Close | High | Low | Open | Volume |
---|---|---|---|---|---|---|
Date | ||||||
2023-12-21 | 1690.00 | 1690.00 | 1765.00 | 1680.00 | 1765.00 | 25310000 |
2023-12-22 | 1695.00 | 1695.00 | 1725.00 | 1685.00 | 1690.00 | 9421600 |
2023-12-27 | 1695.00 | 1695.00 | 1705.00 | 1685.00 | 1695.00 | 10923600 |
2023-12-28 | 1740.00 | 1740.00 | 1745.00 | 1685.00 | 1695.00 | 23222700 |
2023-12-29 | 1740.00 | 1740.00 | 1745.00 | 1710.00 | 1735.00 | 21099100 |
2024-01-02 | 1740.00 | 1740.00 | 1745.00 | 1710.00 | 1740.00 | 13118700 |
2024-01-03 | 1800.00 | 1800.00 | 1830.00 | 1730.00 | 1735.00 | 76511200 |
Reshaping DataFrames
Reshaping data adalah salah satu komponen penting dalam tahapan data wrangling, karena memungkinkan seorang analis untuk mempersiapkan data menjadi bentuk yang sesuai untuk tahap analisa data berikutnya.
stack()
and unstack()
stack()
menumpuk level yang ditentukan dari kolom ke indeks dan sangat berguna pada DataFrames yang memiliki kolom multi-level. Ia melakukannya dengan “menggeser” kolom untuk membuat level baru pada indeksnya.
Hal ini lebih mudah dipahami bila kita hanya melihat contohnya. Perhatikan bahwa stock
memiliki kolom 2 tingkat (Atribut dan Simbol) dan indeks 1 tingkat (Tanggal):
stock.head(2)
Attributes | Adj Close | Close | High | Low | Open | Volume | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Symbols | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS |
Date | ||||||||||||||||||
2020-01-02 | 3717.37 | 3239.33 | 326.18 | 4410.00 | 3875.00 | 332.00 | 4410.00 | 3887.50 | 336.00 | 4360.00 | 3825.00 | 330.00 | 4400.00 | 3837.50 | 330.00 | 41714100 | 37379800 | 1456400 |
2020-01-03 | 3725.80 | 3228.88 | 322.25 | 4420.00 | 3862.50 | 328.00 | 4440.00 | 3912.50 | 336.00 | 4390.00 | 3812.50 | 326.00 | 4420.00 | 3875.00 | 334.00 | 82898300 | 70294600 | 4989600 |
Saat kita menumpuk stock
DataFrame, kita mengecilkan jumlah level pada kolomnya sebanyak satu: stock
sekarang memiliki 1 kolom level bernama Attributes
:
stock.stack()
Attributes | Adj Close | Close | High | Low | Open | Volume | |
---|---|---|---|---|---|---|---|
Date | Symbols | ||||||
2020-01-02 | BBRI | 3717.37 | 4410.00 | 4410.00 | 4360.00 | 4400.00 | 41714100 |
BMRI | 3239.33 | 3875.00 | 3887.50 | 3825.00 | 3837.50 | 37379800 | |
BRIS | 326.18 | 332.00 | 336.00 | 330.00 | 330.00 | 1456400 | |
2020-01-03 | BBRI | 3725.80 | 4420.00 | 4440.00 | 4390.00 | 4420.00 | 82898300 |
BMRI | 3228.88 | 3862.50 | 3912.50 | 3812.50 | 3875.00 | 70294600 | |
... | ... | ... | ... | ... | ... | ... | ... |
2024-01-02 | BMRI | 6125.00 | 6125.00 | 6125.00 | 6025.00 | 6050.00 | 26235700 |
BRIS | 1740.00 | 1740.00 | 1745.00 | 1710.00 | 1740.00 | 13118700 | |
2024-01-03 | BBRI | 5600.00 | 5600.00 | 5650.00 | 5600.00 | 5625.00 | 83659700 |
BMRI | 6100.00 | 6100.00 | 6150.00 | 6050.00 | 6100.00 | 30053900 | |
BRIS | 1800.00 | 1800.00 | 1830.00 | 1730.00 | 1735.00 | 76511200 |
2928 rows × 6 columns
unstack()
melakukan yang sebaliknya: ia “menggeser” level dari sumbu indeks ke sumbu kolom. Coba dan buat tumpukan DataFrame, lalu terapkan unstack
pada DataFrame baru untuk melihatnya kembali ke bentuk aslinya:
## Write your code to try out .unstack() method here
stock.unstack()
Attributes Symbols Date
Adj Close BBRI 2020-01-02 3717.37
2020-01-03 3725.80
2020-01-06 3683.65
2020-01-07 3708.94
2020-01-08 3692.08
...
Volume BRIS 2023-12-27 10923600.00
2023-12-28 23222700.00
2023-12-29 21099100.00
2024-01-02 13118700.00
2024-01-03 76511200.00
Length: 17568, dtype: float64
Dive Deeper
Jawablah pertanyaan-pertanyaan berikut ini untuk memastikan Anda dapat melanjutkan sesi berikutnya:
-
Bagaimana cara menukar posisi (level) Symbols dan Attributes?
-
Berdasarkan pengetahuan Anda, (simbol) perusahaan apa yang layak untuk diinvestasikan? (Anda dapat melihat fluktuasinya, artinya, dll)
# Write your solution code here
# stock.swaplevel(axis=1)
# stock stack + unstack
# stock.stack(level=0).unstack()
stock.stack([1,0]).unstack([1,2])
Symbols | BBRI | BMRI | BRIS | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Attributes | Adj Close | Close | High | Low | Open | Volume | Adj Close | Close | High | Low | Open | Volume | Adj Close | Close | High | Low | Open | Volume |
Date | ||||||||||||||||||
2020-01-02 | 3717.37 | 4410.00 | 4410.00 | 4360.00 | 4400.00 | 41714100.00 | 3239.33 | 3875.00 | 3887.50 | 3825.00 | 3837.50 | 37379800.00 | 326.18 | 332.00 | 336.00 | 330.00 | 330.00 | 1456400.00 |
2020-01-03 | 3725.80 | 4420.00 | 4440.00 | 4390.00 | 4420.00 | 82898300.00 | 3228.88 | 3862.50 | 3912.50 | 3812.50 | 3875.00 | 70294600.00 | 322.25 | 328.00 | 336.00 | 326.00 | 334.00 | 4989600.00 |
2020-01-06 | 3683.65 | 4370.00 | 4390.00 | 4320.00 | 4360.00 | 44225100.00 | 3176.63 | 3800.00 | 3837.50 | 3762.50 | 3825.00 | 61892000.00 | 318.32 | 324.00 | 334.00 | 320.00 | 328.00 | 6937900.00 |
2020-01-07 | 3708.94 | 4400.00 | 4410.00 | 4380.00 | 4410.00 | 103948100.00 | 3176.63 | 3800.00 | 3862.50 | 3787.50 | 3862.50 | 70895600.00 | 312.42 | 318.00 | 324.00 | 316.00 | 324.00 | 6319400.00 |
2020-01-08 | 3692.08 | 4380.00 | 4400.00 | 4340.00 | 4380.00 | 171751200.00 | 3134.83 | 3750.00 | 3775.00 | 3687.50 | 3775.00 | 105080600.00 | 306.53 | 312.00 | 318.00 | 312.00 | 318.00 | 4058800.00 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
2023-12-27 | 5542.47 | 5625.00 | 5725.00 | 5625.00 | 5700.00 | 122236700.00 | 6000.00 | 6000.00 | 6025.00 | 5925.00 | 6000.00 | 43114900.00 | 1695.00 | 1695.00 | 1705.00 | 1685.00 | 1695.00 | 10923600.00 |
2023-12-28 | 5641.00 | 5725.00 | 5750.00 | 5675.00 | 5700.00 | 121434600.00 | 6125.00 | 6125.00 | 6150.00 | 6000.00 | 6050.00 | 75118700.00 | 1740.00 | 1740.00 | 1745.00 | 1685.00 | 1695.00 | 23222700.00 |
2023-12-29 | 5641.00 | 5725.00 | 5750.00 | 5675.00 | 5750.00 | 93126000.00 | 6050.00 | 6050.00 | 6125.00 | 6000.00 | 6125.00 | 63097100.00 | 1740.00 | 1740.00 | 1745.00 | 1710.00 | 1735.00 | 21099100.00 |
2024-01-02 | 5675.00 | 5675.00 | 5675.00 | 5625.00 | 5650.00 | 91143100.00 | 6125.00 | 6125.00 | 6125.00 | 6025.00 | 6050.00 | 26235700.00 | 1740.00 | 1740.00 | 1745.00 | 1710.00 | 1740.00 | 13118700.00 |
2024-01-03 | 5600.00 | 5600.00 | 5650.00 | 5600.00 | 5625.00 | 83659700.00 | 6100.00 | 6100.00 | 6150.00 | 6050.00 | 6100.00 | 30053900.00 | 1800.00 | 1800.00 | 1830.00 | 1730.00 | 1735.00 | 76511200.00 |
976 rows × 18 columns
stock.groupby(level = 1, axis = 1).describe()
count | mean | std | min | 25% | 50% | 75% | max | |||
---|---|---|---|---|---|---|---|---|---|---|
Symbols | Attributes | Symbols | ||||||||
BBRI | Adj Close | BBRI | 976.00 | 3983.76 | 825.93 | 1893.82 | 3530.16 | 3950.26 | 4450.15 | 5675.00 |
Close | BBRI | 976.00 | 4341.34 | 734.56 | 2170.00 | 3997.50 | 4400.00 | 4772.50 | 5725.00 | |
High | BBRI | 976.00 | 4394.92 | 727.07 | 2270.00 | 4070.00 | 4440.00 | 4820.00 | 5750.00 | |
Low | BBRI | 976.00 | 4293.33 | 737.23 | 2160.00 | 3930.00 | 4350.00 | 4722.50 | 5675.00 | |
Open | BBRI | 976.00 | 4347.60 | 731.63 | 2250.00 | 4000.00 | 4400.00 | 4780.00 | 5750.00 | |
Volume | BBRI | 976.00 | 162823853.00 | 99249723.95 | 27676500.00 | 99034175.00 | 136537400.00 | 191963800.00 | 898453700.00 | |
BMRI | Adj Close | BMRI | 976.00 | 3723.45 | 1214.71 | 1633.40 | 2775.37 | 3280.89 | 4780.97 | 10225.00 |
Close | BMRI | 976.00 | 3974.56 | 1110.13 | 1860.00 | 3075.00 | 3775.00 | 5015.62 | 10225.00 | |
High | BMRI | 976.00 | 4024.61 | 1110.79 | 1900.00 | 3125.00 | 3837.50 | 5075.00 | 10400.00 | |
Low | BMRI | 976.00 | 3925.31 | 1106.74 | 1830.00 | 3046.88 | 3750.00 | 4975.00 | 10225.00 | |
Open | BMRI | 976.00 | 3977.00 | 1106.57 | 1880.00 | 3087.50 | 3793.75 | 5025.00 | 10350.00 | |
Volume | BMRI | 976.00 | 105844761.99 | 65129933.21 | 0.00 | 64435950.00 | 91211050.00 | 131406100.00 | 770252400.00 | |
BRIS | Adj Close | BRIS | 976.00 | 1500.02 | 671.26 | 132.63 | 1310.69 | 1561.67 | 1790.75 | 3703.88 |
Close | BRIS | 976.00 | 1517.88 | 682.52 | 135.00 | 1318.75 | 1580.00 | 1810.00 | 3770.00 | |
High | BRIS | 976.00 | 1555.41 | 705.24 | 155.00 | 1350.00 | 1607.50 | 1848.75 | 3980.00 | |
Low | BRIS | 976.00 | 1489.19 | 665.76 | 135.00 | 1300.00 | 1550.00 | 1780.00 | 3710.00 | |
Open | BRIS | 976.00 | 1519.86 | 684.72 | 136.00 | 1315.00 | 1580.00 | 1805.00 | 3800.00 | |
Volume | BRIS | 976.00 | 66363241.09 | 124768967.30 | 664700.00 | 10885025.00 | 23884104.00 | 60038475.00 | 1318651800.00 |
stock['Close'].plot()
<Axes: xlabel='Date'>
Sepertinya saham BBRI paling GACOR !!! Karena selisih high and low secara median dan mean yang cukup bagus, std tidak begitu variatif jadi lebih stabil dan volume yang tinggi sehingga lebih dipercaya masyarakat
melt()
Goal: Melebur beberapa kolom menjadi 1 kolom (variabel) dan nilai di dalamnnya menjadi value `
Syntax:
Dataframe.melt()
❓ Dari dataframe bris
hasil metode cross section (xs
) sebelumnya, aplikasikan method melt()
!
# dataframe bris
bris
Attributes | Adj Close | Close | High | Low | Open | Volume |
---|---|---|---|---|---|---|
Date | ||||||
2020-01-02 | 326.18 | 332.00 | 336.00 | 330.00 | 330.00 | 1456400 |
2020-01-03 | 322.25 | 328.00 | 336.00 | 326.00 | 334.00 | 4989600 |
2020-01-06 | 318.32 | 324.00 | 334.00 | 320.00 | 328.00 | 6937900 |
2020-01-07 | 312.42 | 318.00 | 324.00 | 316.00 | 324.00 | 6319400 |
2020-01-08 | 306.53 | 312.00 | 318.00 | 312.00 | 318.00 | 4058800 |
... | ... | ... | ... | ... | ... | ... |
2023-12-27 | 1695.00 | 1695.00 | 1705.00 | 1685.00 | 1695.00 | 10923600 |
2023-12-28 | 1740.00 | 1740.00 | 1745.00 | 1685.00 | 1695.00 | 23222700 |
2023-12-29 | 1740.00 | 1740.00 | 1745.00 | 1710.00 | 1735.00 | 21099100 |
2024-01-02 | 1740.00 | 1740.00 | 1745.00 | 1710.00 | 1740.00 | 13118700 |
2024-01-03 | 1800.00 | 1800.00 | 1830.00 | 1730.00 | 1735.00 | 76511200 |
976 rows × 6 columns
DataFrame di atas memiliki format wide: terdiri dari __ baris dan 6 kolom. Fungsi melt()
menggabungkan semua kolom menjadi satu dan menyimpan nilai yang sesuai dengan masing-masing kolom, sehingga DataFrame yang dihasilkan memiliki ___ * 6 = 5.382 baris. Selain itu, DataFrame ini juga memiliki kolom Attributes
dan kolom value
.
# your code here
bris.melt(ignore_index=False)
Attributes | value | |
---|---|---|
Date | ||
2020-01-02 | Adj Close | 326.18 |
2020-01-03 | Adj Close | 322.25 |
2020-01-06 | Adj Close | 318.32 |
2020-01-07 | Adj Close | 312.42 |
2020-01-08 | Adj Close | 306.53 |
... | ... | ... |
2023-12-27 | Volume | 10923600.00 |
2023-12-28 | Volume | 23222700.00 |
2023-12-29 | Volume | 21099100.00 |
2024-01-02 | Volume | 13118700.00 |
2024-01-03 | Volume | 76511200.00 |
5856 rows × 2 columns
Data di atas kurang informatif sebab kita tidak tahu kapan nilai-nilai tersebut muncul. Hal ini dikarenakan Date
merupakan index baris.
❓ Bagaimana jika kita ingin Date tetap dimunculkan? Kita perlu mengubah Date
dari index menjadi kolom
Identifier and Value
Dalam method melt()
, terdapat dua parameter yang sering digunakan:
id_vars
: kolom yang dipertahankanvalue_vars
: kolom yang di-melt
# menggunakan reset_index() sehingga Date menjadi kolom
stock_kopi = stock.reset_index().copy()
stock_kopi.tail(5)
Attributes | Date | Adj Close | Close | High | Low | Open | Volume | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Symbols | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | |
971 | 2023-12-27 | 5542.47 | 6000.00 | 1695.00 | 5625.00 | 6000.00 | 1695.00 | 5725.00 | 6025.00 | 1705.00 | 5625.00 | 5925.00 | 1685.00 | 5700.00 | 6000.00 | 1695.00 | 122236700 | 43114900 | 10923600 |
972 | 2023-12-28 | 5641.00 | 6125.00 | 1740.00 | 5725.00 | 6125.00 | 1740.00 | 5750.00 | 6150.00 | 1745.00 | 5675.00 | 6000.00 | 1685.00 | 5700.00 | 6050.00 | 1695.00 | 121434600 | 75118700 | 23222700 |
973 | 2023-12-29 | 5641.00 | 6050.00 | 1740.00 | 5725.00 | 6050.00 | 1740.00 | 5750.00 | 6125.00 | 1745.00 | 5675.00 | 6000.00 | 1710.00 | 5750.00 | 6125.00 | 1735.00 | 93126000 | 63097100 | 21099100 |
974 | 2024-01-02 | 5675.00 | 6125.00 | 1740.00 | 5675.00 | 6125.00 | 1740.00 | 5675.00 | 6125.00 | 1745.00 | 5625.00 | 6025.00 | 1710.00 | 5650.00 | 6050.00 | 1740.00 | 91143100 | 26235700 | 13118700 |
975 | 2024-01-03 | 5600.00 | 6100.00 | 1800.00 | 5600.00 | 6100.00 | 1800.00 | 5650.00 | 6150.00 | 1830.00 | 5600.00 | 6050.00 | 1730.00 | 5625.00 | 6100.00 | 1735.00 | 83659700 | 30053900 | 76511200 |
📌 Note:
Fungsi reset_index
di Pandas digunakan untuk mengembalikan indeks dari DataFrame atau Series ke indeks default yang berurutan (0, 1, 2, …) dan menghapus indeks yang sudah ada
# reset index & melt
stock_kopi.melt()
Attributes | Symbols | value | |
---|---|---|---|
0 | Date | 2020-01-02 00:00:00 | |
1 | Date | 2020-01-03 00:00:00 | |
2 | Date | 2020-01-06 00:00:00 | |
3 | Date | 2020-01-07 00:00:00 | |
4 | Date | 2020-01-08 00:00:00 | |
... | ... | ... | ... |
18539 | Volume | BRIS | 10923600 |
18540 | Volume | BRIS | 23222700 |
18541 | Volume | BRIS | 21099100 |
18542 | Volume | BRIS | 13118700 |
18543 | Volume | BRIS | 76511200 |
18544 rows × 3 columns
# id_vars
stock_kopi.melt(id_vars=['Date'])
Date | Attributes | Symbols | value | |
---|---|---|---|---|
0 | 2020-01-02 | Adj Close | BBRI | 3717.37 |
1 | 2020-01-03 | Adj Close | BBRI | 3725.80 |
2 | 2020-01-06 | Adj Close | BBRI | 3683.65 |
3 | 2020-01-07 | Adj Close | BBRI | 3708.94 |
4 | 2020-01-08 | Adj Close | BBRI | 3692.08 |
... | ... | ... | ... | ... |
17563 | 2023-12-27 | Volume | BRIS | 10923600.00 |
17564 | 2023-12-28 | Volume | BRIS | 23222700.00 |
17565 | 2023-12-29 | Volume | BRIS | 21099100.00 |
17566 | 2024-01-02 | Volume | BRIS | 13118700.00 |
17567 | 2024-01-03 | Volume | BRIS | 76511200.00 |
17568 rows × 4 columns
❓ Lakukan melt terhadap data bris
hanya pada kolom Close
dan Open
, serta setiap observasinya dibedakan berdasarkan Date
.
# bris.reset_index().melt(id_vars=['Date'], value_vars=['Close', 'Open'])
bris.reset_index().melt(id_vars=['Date'], value_vars=['Close', 'Open']).set_index('Date')
Attributes | value | |
---|---|---|
Date | ||
2020-01-02 | Close | 332.00 |
2020-01-03 | Close | 328.00 |
2020-01-06 | Close | 324.00 |
2020-01-07 | Close | 318.00 |
2020-01-08 | Close | 312.00 |
... | ... | ... |
2023-12-27 | Open | 1695.00 |
2023-12-28 | Open | 1695.00 |
2023-12-29 | Open | 1735.00 |
2024-01-02 | Open | 1740.00 |
2024-01-03 | Open | 1735.00 |
1952 rows × 2 columns
Visualisasi Data
Tujuan visualisasi:
- Exploratory: proses mengeksplorasi data untuk mendapatkan sebuah insight.
- Visualisasi yang ditampilkan sederhana
- Analogi: mencari dan mendapatkan batu permata di antara ratusan batu biasa
- Explanatory: proses untuk menjelaskan atau menyajikan insight (explain) yang didapat dari hasil exploratory kepada audience.
- Visualisasi biasanya lebih menarik
- Visualisasi meng-highlight insight secara spesifik
- Analogi: mempoles batu permata dan menawarkannya kepada pembeli
Pada course ini, dititikberatkan pada visualisasi untuk eksplorasi, yaitu menampilkan visualisasi data yang informatif dan tepat sehingga mendapatkan insight.
Pandas
dan Matplotlib
Sampai tahap ini mungkin Anda tidak sabar untuk melakukan visualisasi data di Python. Dengan cukup mudah, kita bisa membuat objek plot matplotlib
dengan hanya menggunakan method .plot()
❗️ Sekarang mari kita coba melakukan visualisasi untuk 50 observasi (baris) terakhir Volume
pada stock
- Index akan menjadi sumbu horizontal pada plot (
Date
) - Nilai akan menjadi sumbu vertikal pada plot
- Masing-masing kolom akan menjadi 1 komponen pada plot, dalam hal ini 1
Symbols
menjadi 1 garis
stock['Volume']
Symbols | BBRI | BMRI | BRIS |
---|---|---|---|
Date | |||
2020-01-02 | 41714100 | 37379800 | 1456400 |
2020-01-03 | 82898300 | 70294600 | 4989600 |
2020-01-06 | 44225100 | 61892000 | 6937900 |
2020-01-07 | 103948100 | 70895600 | 6319400 |
2020-01-08 | 171751200 | 105080600 | 4058800 |
... | ... | ... | ... |
2023-12-27 | 122236700 | 43114900 | 10923600 |
2023-12-28 | 121434600 | 75118700 | 23222700 |
2023-12-29 | 93126000 | 63097100 | 21099100 |
2024-01-02 | 91143100 | 26235700 | 13118700 |
2024-01-03 | 83659700 | 30053900 | 76511200 |
976 rows × 3 columns
# ambil 50 data terakhir dari kolom Volume kemudian lakukan .plot()
stock['Volume'][-50:].plot()
<Axes: xlabel='Date'>
📈 Insight:
🔻 Method plot()
mempermudah kita dalam melakukan visualisasi langsung pada DataFrame, tanpa perlu mengerti cara penggunaan matplotlib
. Kunjungi dokumentasi matplotlib untuk detail mengenai matplotlib
.
🔻 Namun, keterbatasan dari penggunaan plot()
adalah minim kustomisasi dari visualisasi yang ada. Hanya terbatas pada parameter yang ada di dalam method tersebut. Kunjungi dokumentasi method plot.
🔻 Salah satu kustomisasi yang dapat kita lakukan untuk memperindah visualisasi adalah melalui matplotlib style sheet. Kita dapat mengganti nilai ‘default’ pada method plt.style.use()
dengan salah satu style yang tersedia, kemudian jalankan kembali code visualisasi untuk menerapkan style yang dipilih.
import matplotlib.pyplot as plt
print(plt.style.available)
['Solarize_Light2', '_classic_test_patch', '_mpl-gallery', '_mpl-gallery-nogrid', 'bmh', 'classic', 'dark_background', 'fast', 'fivethirtyeight', 'ggplot', 'grayscale', 'seaborn-v0_8', 'seaborn-v0_8-bright', 'seaborn-v0_8-colorblind', 'seaborn-v0_8-dark', 'seaborn-v0_8-dark-palette', 'seaborn-v0_8-darkgrid', 'seaborn-v0_8-deep', 'seaborn-v0_8-muted', 'seaborn-v0_8-notebook', 'seaborn-v0_8-paper', 'seaborn-v0_8-pastel', 'seaborn-v0_8-poster', 'seaborn-v0_8-talk', 'seaborn-v0_8-ticks', 'seaborn-v0_8-white', 'seaborn-v0_8-whitegrid', 'tableau-colorblind10']
# misalnya gunakan style seaborn-v0_8
plt.style.use('seaborn-v0_8-poster')
# ambil 50 data terakhir dari kolom Volume kemudian lakukan .plot()
stock['Volume'].tail(50).plot()
<Axes: xlabel='Date'>
🧐 Task: Ambil data BRIS untuk tanggal 8 September 2022 s.d. 8 September 2023 dan assign ke variabel bris_sept
. Setelah itu lakukan visualisasi dari data bris_sept
tersebut.
Hint: gunakan .loc[start_date : end_date]
bris.tail()
Attributes | Adj Close | Close | High | Low | Open | Volume |
---|---|---|---|---|---|---|
Date | ||||||
2023-12-27 | 1695.00 | 1695.00 | 1705.00 | 1685.00 | 1695.00 | 10923600 |
2023-12-28 | 1740.00 | 1740.00 | 1745.00 | 1685.00 | 1695.00 | 23222700 |
2023-12-29 | 1740.00 | 1740.00 | 1745.00 | 1710.00 | 1735.00 | 21099100 |
2024-01-02 | 1740.00 | 1740.00 | 1745.00 | 1710.00 | 1740.00 | 13118700 |
2024-01-03 | 1800.00 | 1800.00 | 1830.00 | 1730.00 | 1735.00 | 76511200 |
# gunakan .loc untuk mensubset tanggal
bris_sept = bris.loc['2022-09-08':'2023-09-08']
# melakukan visualisasi
bris_sept.plot()
<Axes: xlabel='Date'>
bris_sept.drop(columns='Volume').plot(style='.-')
<Axes: xlabel='Date'>
💭 Diskusi: Apakah visualisasi tersebut sudah cukup informatif dan tepat?
Kurang detail untuk nominalnya karena nilai dari volume terlalu tinggi dibanding yang lain
📌 Types of Visualization
Visualisasi berikut hanya perlu menggunakan satu kolom:
- Data kategorik:
.plot(kind='bar')
untuk barplot (diagram batang).plot(kind='barh')
untuk horizontal barplot.plot(kind='box')
untuk boxplot (five number summary).plot(kind='pie')
untuk pie chart
- Data numerik:
.plot(kind='hist')
untuk histogram.plot(kind='density')
untuk density plot.plot(kind='area')
untuk area plot
Visualisasi berikut perlu menggunakan dua kolom:
.plot(kind='scatter')
untuk scatter plot.plot(kind='hexbin')
untuk hexagonal bin plot
💡 Panduan untuk menentukan tipe visualisasi yang tepat: https://www.data-to-viz.com/
Silakan mengacu referensi lengkapnya di official documentation untuk method plot
apabila ingin eksplor visualisasi yang ada di luar lingkup course ini
📊 Barplot
Visualisasi untuk melihat perbandingan nilai dari beberapa kategori
❓ Menggunakan data stock
, tampilkan visualisasi untuk membandingkan fluktuasi (menggunakan coefficient of variance) nilai Close
pada masing-masing Symbols
. Mana saham yang paling berfluktuasi?
Info lebih lanjut terkait coefficient of variance
# mengambil nilai coefficient of variation
coef_of_var = stock['High'].std() / stock['High'].mean()
coef_of_var
Symbols
BBRI 0.17
BMRI 0.28
BRIS 0.45
dtype: float64
(stock['Close']-stock['Open']).plot(kind='box')
<Axes: >
# Visualisasi barplot
coef_of_var.plot(kind='bar')
<Axes: xlabel='Symbols'>
📈 Insight:
…
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(bris_sept.loc[:, bris_sept.columns != 'Volume'])
ax_vol = ax.twinx()
ax_vol.bar(bris_sept.index, bris_sept['Volume'], color='blue', alpha=0.3, label='Volume')
ax_vol.set_ylabel('Volume')
ax_vol.legend(loc='upper right')
plt.show()
# (opsional) ingin diurutkan
coef_of_var.sort_values(ascending = False).plot(kind='bar')
<Axes: xlabel='Symbols'>
Histogram
Visualisasi untuk melihat persebaran data
Menggunakan data bbri
, tampilkan visualisasi histogram untuk mengetahui persebaran Volume
pada saham BBRI
:
# slicing volume BBRI, masukan ke variabel vol_bbri
bbri = stock['Volume']['BBRI']
# visualisasi
bbri.hist().xaxis.set_major_formatter('{x:1.0f}')
📈 Insight:
- Transaksi terbanyak terjadi di persebaran di 0-200 juta
Group By: Aggregation Table
Teknik yang tak kalah penting adalah operasi group by. Mungkin untuk Anda yang sudah pernah menggunakan SQL akan familiar dengan operasi group by ini.
❗️ Misalkan kita punya dataframe close_melted
yang ingin kita bandingkan nilai Close
hariannya pada saham BRIS, BBRI, dan BMRI:
close = stock['Close']
close_melted = close.reset_index().melt(id_vars = 'Date', value_name = 'Close')
close_melted
Date | Symbols | Close | |
---|---|---|---|
0 | 2020-01-02 | BBRI | 4410.00 |
1 | 2020-01-03 | BBRI | 4420.00 |
2 | 2020-01-06 | BBRI | 4370.00 |
3 | 2020-01-07 | BBRI | 4400.00 |
4 | 2020-01-08 | BBRI | 4380.00 |
... | ... | ... | ... |
2923 | 2023-12-27 | BRIS | 1695.00 |
2924 | 2023-12-28 | BRIS | 1740.00 |
2925 | 2023-12-29 | BRIS | 1740.00 |
2926 | 2024-01-02 | BRIS | 1740.00 |
2927 | 2024-01-03 | BRIS | 1800.00 |
2928 rows × 3 columns
❓ Di antara saham BRIS, BBRI, maupun BMRI, manakah saham yang memiliki rata-rata Close
harian tertinggi?
Cobalah preprocessing datanya menggunakan .groupby()
.
Syntax: [df_name].groupby(by=[column_name]).aggfunc_name()
# coba pakai method yang sudah dipelajari
stock.groupby(level=1, axis=1).mean()
Symbols | BBRI | BMRI | BRIS |
---|---|---|---|
Date | |||
2020-01-02 | 6955899.56 | 6233077.39 | 243009.03 |
2020-01-03 | 13819949.30 | 11718881.90 | 831874.37 |
2020-01-06 | 7374370.61 | 10318400.27 | 1156587.39 |
2020-01-07 | 17328234.82 | 11819014.86 | 1053499.07 |
2020-01-08 | 28628732.01 | 17516453.72 | 676727.75 |
... | ... | ... | ... |
2023-12-27 | 20377486.24 | 7190808.33 | 1822012.50 |
2023-12-28 | 20243848.50 | 12524858.33 | 3871884.17 |
2023-12-29 | 15525756.83 | 10521241.67 | 3517961.67 |
2024-01-02 | 15195233.33 | 4377691.67 | 2187895.83 |
2024-01-03 | 13947962.50 | 5014066.67 | 12753349.17 |
976 rows × 3 columns
# coba pakai groupby
avg_close = close_melted.groupby(by = 'Symbols').mean()['Close']
avg_close
Symbols
BBRI 4341.34
BMRI 3974.56
BRIS 1517.88
Name: Close, dtype: float64
# visualisasi bar chart
avg_close.plot(kind = 'bar')
<Axes: xlabel='Symbols'>
Grouped Bar Chart
Kita akan coba melakukan visualisasi grouped bar chart untuk membandingkan rata-rata nilai Close
untuk ketiga saham setiap bulannya
1️⃣ Step 1: Panggil kembali dataframe close
yang sudah dibuat sebelumnya
# dataframe close
close.head()
Symbols | BBRI | BMRI | BRIS |
---|---|---|---|
Date | |||
2020-01-02 | 4410.00 | 3875.00 | 332.00 |
2020-01-03 | 4420.00 | 3862.50 | 328.00 |
2020-01-06 | 4370.00 | 3800.00 | 324.00 |
2020-01-07 | 4400.00 | 3800.00 | 318.00 |
2020-01-08 | 4380.00 | 3750.00 | 312.00 |
2️⃣ Step 2: Buatlah kolom Month
yang berisikan nama bulan pada dataframe close
📌 Note: untuk mengambil nama bulan tidak perlu .dt
lagi, karena sudah berupa objek DatetimeIndex. Jika date ada di dalam kolom maka perlu menggunakan .dt
close.loc[:,'Month'] = close.index.month_name()
close.head()
Symbols | BBRI | BMRI | BRIS | Month |
---|---|---|---|---|
Date | ||||
2020-01-02 | 4410.00 | 3875.00 | 332.00 | January |
2020-01-03 | 4420.00 | 3862.50 | 328.00 | January |
2020-01-06 | 4370.00 | 3800.00 | 324.00 | January |
2020-01-07 | 4400.00 | 3800.00 | 318.00 | January |
2020-01-08 | 4380.00 | 3750.00 | 312.00 | January |
3️⃣ Step 3: Membuat .groupby()
untuk mendapatkan mean Close tiap bulan
close_mean = close.groupby(by=['Month']).mean()
4️⃣ Step 4: Visualisasikan group barchart
# visualisasi barchart
close_mean.plot(kind = 'bar')
<Axes: xlabel='Month'>
5️⃣ Step 5: Improvement Visualisasi
# perbaiki urutan bulan
months= ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
close_mean.loc[months,].plot(kind='bar')
<Axes: xlabel='Month'>
stock.loc[:, stock.columns!='Volume']
Attributes | Adj Close | Close | High | Low | Open | Volume | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Symbols | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS | BBRI | BMRI | BRIS |
Date | ||||||||||||||||||
2020-01-02 | 3717.37 | 3239.33 | 326.18 | 4410.00 | 3875.00 | 332.00 | 4410.00 | 3887.50 | 336.00 | 4360.00 | 3825.00 | 330.00 | 4400.00 | 3837.50 | 330.00 | 41714100 | 37379800 | 1456400 |
2020-01-03 | 3725.80 | 3228.88 | 322.25 | 4420.00 | 3862.50 | 328.00 | 4440.00 | 3912.50 | 336.00 | 4390.00 | 3812.50 | 326.00 | 4420.00 | 3875.00 | 334.00 | 82898300 | 70294600 | 4989600 |
2020-01-06 | 3683.65 | 3176.63 | 318.32 | 4370.00 | 3800.00 | 324.00 | 4390.00 | 3837.50 | 334.00 | 4320.00 | 3762.50 | 320.00 | 4360.00 | 3825.00 | 328.00 | 44225100 | 61892000 | 6937900 |
2020-01-07 | 3708.94 | 3176.63 | 312.42 | 4400.00 | 3800.00 | 318.00 | 4410.00 | 3862.50 | 324.00 | 4380.00 | 3787.50 | 316.00 | 4410.00 | 3862.50 | 324.00 | 103948100 | 70895600 | 6319400 |
2020-01-08 | 3692.08 | 3134.83 | 306.53 | 4380.00 | 3750.00 | 312.00 | 4400.00 | 3775.00 | 318.00 | 4340.00 | 3687.50 | 312.00 | 4380.00 | 3775.00 | 318.00 | 171751200 | 105080600 | 4058800 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
2023-12-27 | 5542.47 | 6000.00 | 1695.00 | 5625.00 | 6000.00 | 1695.00 | 5725.00 | 6025.00 | 1705.00 | 5625.00 | 5925.00 | 1685.00 | 5700.00 | 6000.00 | 1695.00 | 122236700 | 43114900 | 10923600 |
2023-12-28 | 5641.00 | 6125.00 | 1740.00 | 5725.00 | 6125.00 | 1740.00 | 5750.00 | 6150.00 | 1745.00 | 5675.00 | 6000.00 | 1685.00 | 5700.00 | 6050.00 | 1695.00 | 121434600 | 75118700 | 23222700 |
2023-12-29 | 5641.00 | 6050.00 | 1740.00 | 5725.00 | 6050.00 | 1740.00 | 5750.00 | 6125.00 | 1745.00 | 5675.00 | 6000.00 | 1710.00 | 5750.00 | 6125.00 | 1735.00 | 93126000 | 63097100 | 21099100 |
2024-01-02 | 5675.00 | 6125.00 | 1740.00 | 5675.00 | 6125.00 | 1740.00 | 5675.00 | 6125.00 | 1745.00 | 5625.00 | 6025.00 | 1710.00 | 5650.00 | 6050.00 | 1740.00 | 91143100 | 26235700 | 13118700 |
2024-01-03 | 5600.00 | 6100.00 | 1800.00 | 5600.00 | 6100.00 | 1800.00 | 5650.00 | 6150.00 | 1830.00 | 5600.00 | 6050.00 | 1730.00 | 5625.00 | 6100.00 | 1735.00 | 83659700 | 30053900 | 76511200 |
976 rows × 18 columns
Menggabungkan agg
dan groupby
stock_long = stock.stack().reset_index()
stock_long
Attributes | Date | Symbols | Adj Close | Close | High | Low | Open | Volume |
---|---|---|---|---|---|---|---|---|
0 | 2020-01-02 | BBRI | 3717.37 | 4410.00 | 4410.00 | 4360.00 | 4400.00 | 41714100 |
1 | 2020-01-02 | BMRI | 3239.33 | 3875.00 | 3887.50 | 3825.00 | 3837.50 | 37379800 |
2 | 2020-01-02 | BRIS | 326.18 | 332.00 | 336.00 | 330.00 | 330.00 | 1456400 |
3 | 2020-01-03 | BBRI | 3725.80 | 4420.00 | 4440.00 | 4390.00 | 4420.00 | 82898300 |
4 | 2020-01-03 | BMRI | 3228.88 | 3862.50 | 3912.50 | 3812.50 | 3875.00 | 70294600 |
... | ... | ... | ... | ... | ... | ... | ... | ... |
2923 | 2024-01-02 | BMRI | 6125.00 | 6125.00 | 6125.00 | 6025.00 | 6050.00 | 26235700 |
2924 | 2024-01-02 | BRIS | 1740.00 | 1740.00 | 1745.00 | 1710.00 | 1740.00 | 13118700 |
2925 | 2024-01-03 | BBRI | 5600.00 | 5600.00 | 5650.00 | 5600.00 | 5625.00 | 83659700 |
2926 | 2024-01-03 | BMRI | 6100.00 | 6100.00 | 6150.00 | 6050.00 | 6100.00 | 30053900 |
2927 | 2024-01-03 | BRIS | 1800.00 | 1800.00 | 1830.00 | 1730.00 | 1735.00 | 76511200 |
2928 rows × 8 columns
Misalkan kita ingin membuat tabel agregasi dengan aggfunc
yang berbeda-beda untuk masing-masing Symbols
berupa:
- Maximum
stock
price (max
dariHigh
) - Minimum
stock
price (min
dariLow
) - Rata-rata closing price (
mean
dariClose
)
Untuk mendapat hasil tersebut, kita harus melakukan chaining groupby
dengan method agg
. Kita harus menyertakan mapping (dictionary) untuk setiap kolom dengan fungsi agregasinya seperti berikut ini:
Syntax:
.agg({
'NAMA_KOLOM': 'FUNGSI_AGREGASI'
})
summary_stock = stock_long.groupby('Symbols').agg({
'High' : 'max',
'Low' : 'min',
'Close' : 'mean'
})
summary_stock
Attributes | High | Low | Close |
---|---|---|---|
Symbols | |||
BBRI | 5750.00 | 2160.00 | 4341.34 |
BMRI | 10400.00 | 1830.00 | 3974.56 |
BRIS | 3980.00 | 135.00 | 1517.88 |
❓ Visualisasikan tabel agregasi di atas untuk membandingkan nilai tersebut.
# visualisasi
summary_stock.plot(kind = 'bar')
<Axes: xlabel='Symbols'>
Leave a comment