WebScraping from 2021/11/26
在台灣電力公司的電力交易平台中,日前輔助服務市場項目中有歷史結清價格與交易量資料。電力的項目分為即時備轉以及補充備轉,得標的單位分為國營與民間,或者非交易的得標容量,而非交易的暫不考慮。而結清價格與得標容量以小時為單位,因此每一小時有即時備轉得標容量(國營)、即時備轉得標容量(民營)、即時備轉結清價格、補充備轉得標容量(國營)、補充備轉得標容量(民營)、補充備轉結清價格六筆資料。資料自2021年11月26日開始每日更新。連結為https://etp.taipower.com.tw/web/service_market/historical_settlement_trading。
而在歷史結清價格與交易量的頁面只有每日以得標容量形成的堆疊柱狀圖加上結清價格的折線圖,滑鼠移至點上會出現容量和價格數字,目的是抓取所有的數字。在網頁前端內中有所有歷史數據,在JavaScript架構下以JSON格式儲存,目標是將資料抓取後轉成R資料格式再輸出,並且計算每日總得標容量以及每月平均電價。
rvest是使用R進行網路爬蟲中重要的套件,jsonlite套件可以操作json格式的資料,lubridate可以進行日期時間格式的轉換,openxlsx可以操作excel檔案。
library(rvest)
library(magrittr)
library(jsonlite)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(lubridate)
##
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
##
## date, intersect, setdiff, union
library(openxlsx)
電力交易平台儲存資料的位置是網址+日期,因此需要自開始日至今日天數個網址,再進行迭代。
首先生成一個從2021/11/16至今天的字串向量。date()會將括號內的字串轉換成日期格式,Sys.Date()會返回當前系統的日期,seq()會建立序列,需要指定開始、結尾、間隔,如下表示自2021/11/16開始自今天建立序列,間隔為一天。此時生成的向量格式為日期,使用as.character()將日期轉換成字串,儲存為名為dat的物件。
date("2021-11-16")
## [1] "2021-11-16"
Sys.Date()
## [1] "2023-02-03"
head(seq(from = date('2021-11-16'), to = Sys.Date(), by = 1))
## [1] "2021-11-16" "2021-11-17" "2021-11-18" "2021-11-19" "2021-11-20"
## [6] "2021-11-21"
dat <- as.character(
seq(from = date("2021-11-16"), to = Sys.Date(), by = 1))
head(dat)
## [1] "2021-11-16" "2021-11-17" "2021-11-18" "2021-11-19" "2021-11-20"
## [6] "2021-11-21"
在稍後抓取的資料中,需要選取我們需要的變量,因此先創立需要變量的向量,方便選取。datetime是日期時間,sr是即時備轉,sup字首是補充備轉,Bid字尾是得標容量(國營),BidQse是得標容量(民營),price是結清價格。得標容量的單位都是百萬瓦(MW),而價格的單位是百萬瓦/小時(元/MW·h)。
var <- c("datetime", "srBid", "srBidQse", "srPrice", "supBid", "supBidQse", "supPrice")
為了儲存下載的資料,我們創立一個空物件df用來儲存。
df <- NULL
由於迭代的過程不易理解其中的步驟,因此我們先用2021/11/16為例,了解整個爬蟲以及資料轉換的過程後,再使用迭代方式,其實R更方便進行操作的方式是使用apply家族的函數運算,但方式稍微抽象,因此未來有機會再說明。
url為我們要查詢的網址位置,為固定內容加上要查詢的日期,可以直接將該網址使用瀏覽器查詢,https://etp.taipower.com.tw/api/infoboard/settle_value/query?startDate=2021-11-16,可以直接到該為止,在軟體中,url多代表想要查詢的位置。
url <- paste0("https://etp.taipower.com.tw/api/infoboard/settle_value/query?startDate=",
as.character(date('2021-11-16')))
url
## [1] "https://etp.taipower.com.tw/api/infoboard/settle_value/query?startDate=2021-11-16"
使用rvest套件中的read_html()讀取網頁,網頁是由許多節點組成,下列出現我們最初讀取到的內容。我們想要的是在節點p下的data物件。
read_html(url)
## {html_document}
## <html>
## [1] <body><p>{"msg":"操作成功","code":200,"data":[{"tranDate":"2021-11-16","tranH ...
read_html(url) %>%
html_nodes('p')
## {xml_nodeset (1)}
## [1] <p>{"msg":"操作成功","code":200,"data":[{"tranDate":"2021-11-16","tranHour":" ...
接下來我們想要將節點內的東西轉成R的dataframe格式,先用html_text()將網頁內容轉成文字格式,再用fromJSON以json格式方式轉換。
read_html(url) %>%
html_nodes('p') %>%
html_text %>%
fromJSON()
## $msg
## [1] "操作成功"
##
## $code
## [1] 200
##
## $data
## tranDate tranHour marginalPrice regBid regBidQse regBidNontrade regDemand
## 1 2021-11-16 00:00 2447.016 105.0 14 681.0 500
## 2 2021-11-16 01:00 2413.235 105.0 14 681.0 500
## 3 2021-11-16 02:00 2273.417 105.0 14 681.0 500
## 4 2021-11-16 03:00 2199.381 281.0 14 505.0 500
## 5 2021-11-16 04:00 2413.235 281.0 14 505.0 500
## 6 2021-11-16 05:00 2290.265 281.0 14 505.0 500
## 7 2021-11-16 06:00 2273.417 281.0 14 505.0 500
## 8 2021-11-16 07:00 2343.366 281.0 14 505.0 500
## 9 2021-11-16 08:00 2473.417 219.4 14 566.8 500
## 10 2021-11-16 09:00 2752.809 80.0 14 706.1 500
## 11 2021-11-16 10:00 2647.016 80.0 14 706.1 500
## 12 2021-11-16 11:00 2879.899 80.0 14 706.1 500
## 13 2021-11-16 12:00 2647.016 108.9 14 677.3 500
## 14 2021-11-16 13:00 2794.398 80.0 14 706.1 500
## 15 2021-11-16 14:00 3556.155 80.0 14 706.2 500
## 16 2021-11-16 15:00 4010.084 80.0 14 706.2 500
## 17 2021-11-16 16:00 4101.844 80.0 14 706.2 500
## 18 2021-11-16 17:00 4101.844 80.0 14 706.3 500
## 19 2021-11-16 18:00 4101.844 80.0 14 706.2 500
## 20 2021-11-16 19:00 4101.844 80.0 14 706.3 500
## 21 2021-11-16 20:00 4101.844 80.0 14 706.2 500
## 22 2021-11-16 21:00 4101.844 80.0 14 706.1 500
## 23 2021-11-16 22:00 3892.572 92.6 14 693.6 500
## 24 2021-11-16 23:00 3724.364 80.0 14 706.0 500
## regOffering regPrice regRegistered srBid srBidQse srBidNontrade srDemand
## 1 1232.9 550 31498.9 376.0 1 623.0 500
## 2 1232.9 550 31498.9 346.0 1 653.0 500
## 3 1232.9 550 31498.9 254.0 1 745.0 500
## 4 1232.9 600 31498.9 363.0 1 636.0 500
## 5 1232.9 600 31498.9 346.0 1 653.0 500
## 6 1232.9 600 31498.9 361.2 1 638.0 500
## 7 1232.9 600 31498.9 363.0 1 636.1 500
## 8 1232.9 600 31498.9 346.0 1 653.0 500
## 9 1232.9 600 31498.9 401.6 1 597.6 500
## 10 1232.9 595 31498.9 340.0 1 659.0 500
## 11 1232.9 595 31498.9 376.0 1 623.1 500
## 12 1232.9 595 31498.9 320.3 0 679.9 500
## 13 1232.9 600 31498.9 415.0 0 585.2 500
## 14 1232.9 595 31498.9 376.0 0 624.0 500
## 15 1232.9 595 31498.9 350.0 1 649.0 500
## 16 1232.9 600 31498.9 310.0 1 689.0 500
## 17 1232.9 595 31498.9 307.3 1 691.8 500
## 18 1232.9 595 31498.9 307.3 1 691.9 500
## 19 1232.9 595 31498.9 307.3 1 692.1 500
## 20 1232.9 595 31498.9 307.3 1 692.0 500
## 21 1232.9 595 31498.9 307.3 1 691.9 500
## 22 1232.9 595 31498.9 310.0 1 689.2 500
## 23 1232.9 600 31498.9 310.0 1 689.0 500
## 24 1232.9 600 31498.9 350.0 1 649.1 500
## srOffering srPrice srRegistered supBid supBidQse supBidNontrade supDemand
## 1 4854.444 400 10215.64 869.7 0 130.5 1000
## 2 4854.444 400 10215.64 823.1 0 177.2 1000
## 3 4854.444 400 10215.64 809.4 0 190.9 1000
## 4 4854.444 400 10215.64 759.3 0 241.2 1000
## 5 4854.444 400 10215.64 739.9 0 260.7 1000
## 6 4854.444 400 10215.64 844.5 0 155.9 1000
## 7 4854.444 400 10215.64 839.4 0 161.0 1000
## 8 4854.444 400 10215.64 685.4 0 315.1 1000
## 9 4854.444 400 10215.64 940.1 0 60.1 1000
## 10 4854.444 400 10215.64 872.2 0 127.9 1000
## 11 4854.444 400 10215.64 907.9 0 92.2 1000
## 12 4853.444 400 10215.64 915.2 0 84.9 1000
## 13 4853.444 400 10215.64 873.0 0 127.1 1000
## 14 4853.444 400 10215.64 922.2 0 78.0 1000
## 15 4854.444 400 10215.64 867.8 0 132.7 1000
## 16 4854.444 400 10215.64 893.3 0 107.0 1000
## 17 4854.444 400 10215.64 765.3 0 235.2 1000
## 18 4854.444 400 10215.64 856.3 0 144.1 1000
## 19 4829.444 400 10215.64 524.1 0 33.2 1000
## 20 4854.444 400 10215.64 859.4 0 140.7 1000
## 21 4854.444 400 10215.64 843.6 0 156.6 1000
## 22 4854.444 400 10215.64 991.6 0 8.6 1000
## 23 4854.444 400 10215.64 922.2 0 78.0 1000
## 24 4854.444 400 10215.64 902.6 0 97.5 1000
## supOffering supPrice supRegistered
## 1 7437.194 350 14174.55
## 2 7437.194 350 14174.55
## 3 7437.194 350 14174.55
## 4 7437.194 350 14174.55
## 5 7437.194 350 14174.55
## 6 7437.194 350 14174.55
## 7 7437.194 350 14174.55
## 8 7437.194 350 14174.55
## 9 7437.194 350 14174.55
## 10 7437.194 350 14174.55
## 11 7437.194 350 14174.55
## 12 7437.194 350 14174.55
## 13 7437.194 350 14174.55
## 14 7437.194 350 14174.55
## 15 7437.194 350 14174.55
## 16 7437.194 350 14174.55
## 17 7437.194 350 14174.55
## 18 7437.194 350 14174.55
## 19 7397.194 350 14174.55
## 20 7437.194 350 14174.55
## 21 7437.194 350 14174.55
## 22 7437.194 350 14174.55
## 23 7437.194 350 14174.55
## 24 7437.194 350 14174.55
若是針對json檔案可以直接使用url進行查詢和轉換。
dfi <- fromJSON(url)
dfi
## $msg
## [1] "操作成功"
##
## $code
## [1] 200
##
## $data
## tranDate tranHour marginalPrice regBid regBidQse regBidNontrade regDemand
## 1 2021-11-16 00:00 2447.016 105.0 14 681.0 500
## 2 2021-11-16 01:00 2413.235 105.0 14 681.0 500
## 3 2021-11-16 02:00 2273.417 105.0 14 681.0 500
## 4 2021-11-16 03:00 2199.381 281.0 14 505.0 500
## 5 2021-11-16 04:00 2413.235 281.0 14 505.0 500
## 6 2021-11-16 05:00 2290.265 281.0 14 505.0 500
## 7 2021-11-16 06:00 2273.417 281.0 14 505.0 500
## 8 2021-11-16 07:00 2343.366 281.0 14 505.0 500
## 9 2021-11-16 08:00 2473.417 219.4 14 566.8 500
## 10 2021-11-16 09:00 2752.809 80.0 14 706.1 500
## 11 2021-11-16 10:00 2647.016 80.0 14 706.1 500
## 12 2021-11-16 11:00 2879.899 80.0 14 706.1 500
## 13 2021-11-16 12:00 2647.016 108.9 14 677.3 500
## 14 2021-11-16 13:00 2794.398 80.0 14 706.1 500
## 15 2021-11-16 14:00 3556.155 80.0 14 706.2 500
## 16 2021-11-16 15:00 4010.084 80.0 14 706.2 500
## 17 2021-11-16 16:00 4101.844 80.0 14 706.2 500
## 18 2021-11-16 17:00 4101.844 80.0 14 706.3 500
## 19 2021-11-16 18:00 4101.844 80.0 14 706.2 500
## 20 2021-11-16 19:00 4101.844 80.0 14 706.3 500
## 21 2021-11-16 20:00 4101.844 80.0 14 706.2 500
## 22 2021-11-16 21:00 4101.844 80.0 14 706.1 500
## 23 2021-11-16 22:00 3892.572 92.6 14 693.6 500
## 24 2021-11-16 23:00 3724.364 80.0 14 706.0 500
## regOffering regPrice regRegistered srBid srBidQse srBidNontrade srDemand
## 1 1232.9 550 31498.9 376.0 1 623.0 500
## 2 1232.9 550 31498.9 346.0 1 653.0 500
## 3 1232.9 550 31498.9 254.0 1 745.0 500
## 4 1232.9 600 31498.9 363.0 1 636.0 500
## 5 1232.9 600 31498.9 346.0 1 653.0 500
## 6 1232.9 600 31498.9 361.2 1 638.0 500
## 7 1232.9 600 31498.9 363.0 1 636.1 500
## 8 1232.9 600 31498.9 346.0 1 653.0 500
## 9 1232.9 600 31498.9 401.6 1 597.6 500
## 10 1232.9 595 31498.9 340.0 1 659.0 500
## 11 1232.9 595 31498.9 376.0 1 623.1 500
## 12 1232.9 595 31498.9 320.3 0 679.9 500
## 13 1232.9 600 31498.9 415.0 0 585.2 500
## 14 1232.9 595 31498.9 376.0 0 624.0 500
## 15 1232.9 595 31498.9 350.0 1 649.0 500
## 16 1232.9 600 31498.9 310.0 1 689.0 500
## 17 1232.9 595 31498.9 307.3 1 691.8 500
## 18 1232.9 595 31498.9 307.3 1 691.9 500
## 19 1232.9 595 31498.9 307.3 1 692.1 500
## 20 1232.9 595 31498.9 307.3 1 692.0 500
## 21 1232.9 595 31498.9 307.3 1 691.9 500
## 22 1232.9 595 31498.9 310.0 1 689.2 500
## 23 1232.9 600 31498.9 310.0 1 689.0 500
## 24 1232.9 600 31498.9 350.0 1 649.1 500
## srOffering srPrice srRegistered supBid supBidQse supBidNontrade supDemand
## 1 4854.444 400 10215.64 869.7 0 130.5 1000
## 2 4854.444 400 10215.64 823.1 0 177.2 1000
## 3 4854.444 400 10215.64 809.4 0 190.9 1000
## 4 4854.444 400 10215.64 759.3 0 241.2 1000
## 5 4854.444 400 10215.64 739.9 0 260.7 1000
## 6 4854.444 400 10215.64 844.5 0 155.9 1000
## 7 4854.444 400 10215.64 839.4 0 161.0 1000
## 8 4854.444 400 10215.64 685.4 0 315.1 1000
## 9 4854.444 400 10215.64 940.1 0 60.1 1000
## 10 4854.444 400 10215.64 872.2 0 127.9 1000
## 11 4854.444 400 10215.64 907.9 0 92.2 1000
## 12 4853.444 400 10215.64 915.2 0 84.9 1000
## 13 4853.444 400 10215.64 873.0 0 127.1 1000
## 14 4853.444 400 10215.64 922.2 0 78.0 1000
## 15 4854.444 400 10215.64 867.8 0 132.7 1000
## 16 4854.444 400 10215.64 893.3 0 107.0 1000
## 17 4854.444 400 10215.64 765.3 0 235.2 1000
## 18 4854.444 400 10215.64 856.3 0 144.1 1000
## 19 4829.444 400 10215.64 524.1 0 33.2 1000
## 20 4854.444 400 10215.64 859.4 0 140.7 1000
## 21 4854.444 400 10215.64 843.6 0 156.6 1000
## 22 4854.444 400 10215.64 991.6 0 8.6 1000
## 23 4854.444 400 10215.64 922.2 0 78.0 1000
## 24 4854.444 400 10215.64 902.6 0 97.5 1000
## supOffering supPrice supRegistered
## 1 7437.194 350 14174.55
## 2 7437.194 350 14174.55
## 3 7437.194 350 14174.55
## 4 7437.194 350 14174.55
## 5 7437.194 350 14174.55
## 6 7437.194 350 14174.55
## 7 7437.194 350 14174.55
## 8 7437.194 350 14174.55
## 9 7437.194 350 14174.55
## 10 7437.194 350 14174.55
## 11 7437.194 350 14174.55
## 12 7437.194 350 14174.55
## 13 7437.194 350 14174.55
## 14 7437.194 350 14174.55
## 15 7437.194 350 14174.55
## 16 7437.194 350 14174.55
## 17 7437.194 350 14174.55
## 18 7437.194 350 14174.55
## 19 7397.194 350 14174.55
## 20 7437.194 350 14174.55
## 21 7437.194 350 14174.55
## 22 7437.194 350 14174.55
## 23 7437.194 350 14174.55
## 24 7437.194 350 14174.55
選取json中名為的data物件,則dfi即為一個dataframe物件。
dfi <- dfi$data
在資料中分別有日期以及時間兩個變項,而我們想要將兩個變項tranDate、tranHour合成為一個日期時間datetime格式的變項。ymd_hm()可以將year/month/day hour:minute排列方式的資料轉換成日期時間格式,有許多不同格式相同功能的函數可以使用。mutate則是新增欄位,等式左邊為新增變數名,等式右邊為新增變數的內容。
dfi <- mutate(.data = dfi,
datetime = ymd_hm(paste0(tranDate, " ", tranHour)))
dfi$datetime
## [1] "2021-11-16 00:00:00 UTC" "2021-11-16 01:00:00 UTC"
## [3] "2021-11-16 02:00:00 UTC" "2021-11-16 03:00:00 UTC"
## [5] "2021-11-16 04:00:00 UTC" "2021-11-16 05:00:00 UTC"
## [7] "2021-11-16 06:00:00 UTC" "2021-11-16 07:00:00 UTC"
## [9] "2021-11-16 08:00:00 UTC" "2021-11-16 09:00:00 UTC"
## [11] "2021-11-16 10:00:00 UTC" "2021-11-16 11:00:00 UTC"
## [13] "2021-11-16 12:00:00 UTC" "2021-11-16 13:00:00 UTC"
## [15] "2021-11-16 14:00:00 UTC" "2021-11-16 15:00:00 UTC"
## [17] "2021-11-16 16:00:00 UTC" "2021-11-16 17:00:00 UTC"
## [19] "2021-11-16 18:00:00 UTC" "2021-11-16 19:00:00 UTC"
## [21] "2021-11-16 20:00:00 UTC" "2021-11-16 21:00:00 UTC"
## [23] "2021-11-16 22:00:00 UTC" "2021-11-16 23:00:00 UTC"
由於資料匡中有許多不必要的變數,因此我們使用select()選取需要的變數,我們先前已經有用var儲存想要的變數,將其條件放入select函數中。
select(.data = dfi, var)
## Warning: Using an external vector in selections was deprecated in tidyselect 1.1.0.
## ℹ Please use `all_of()` or `any_of()` instead.
## # Was:
## data %>% select(var)
##
## # Now:
## data %>% select(all_of(var))
##
## See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
## datetime srBid srBidQse srPrice supBid supBidQse supPrice
## 1 2021-11-16 00:00:00 376.0 1 400 869.7 0 350
## 2 2021-11-16 01:00:00 346.0 1 400 823.1 0 350
## 3 2021-11-16 02:00:00 254.0 1 400 809.4 0 350
## 4 2021-11-16 03:00:00 363.0 1 400 759.3 0 350
## 5 2021-11-16 04:00:00 346.0 1 400 739.9 0 350
## 6 2021-11-16 05:00:00 361.2 1 400 844.5 0 350
## 7 2021-11-16 06:00:00 363.0 1 400 839.4 0 350
## 8 2021-11-16 07:00:00 346.0 1 400 685.4 0 350
## 9 2021-11-16 08:00:00 401.6 1 400 940.1 0 350
## 10 2021-11-16 09:00:00 340.0 1 400 872.2 0 350
## 11 2021-11-16 10:00:00 376.0 1 400 907.9 0 350
## 12 2021-11-16 11:00:00 320.3 0 400 915.2 0 350
## 13 2021-11-16 12:00:00 415.0 0 400 873.0 0 350
## 14 2021-11-16 13:00:00 376.0 0 400 922.2 0 350
## 15 2021-11-16 14:00:00 350.0 1 400 867.8 0 350
## 16 2021-11-16 15:00:00 310.0 1 400 893.3 0 350
## 17 2021-11-16 16:00:00 307.3 1 400 765.3 0 350
## 18 2021-11-16 17:00:00 307.3 1 400 856.3 0 350
## 19 2021-11-16 18:00:00 307.3 1 400 524.1 0 350
## 20 2021-11-16 19:00:00 307.3 1 400 859.4 0 350
## 21 2021-11-16 20:00:00 307.3 1 400 843.6 0 350
## 22 2021-11-16 21:00:00 310.0 1 400 991.6 0 350
## 23 2021-11-16 22:00:00 310.0 1 400 922.2 0 350
## 24 2021-11-16 23:00:00 350.0 1 400 902.6 0 350
這就是我們需要在每天的資料中抓取的資料,將dfi中的內容併入df中,rbind會根據row方向合併資料框。接下來將使用迴圈完成所有操作。
df <- rbind(df, dfi)
df <- NULL
for (i in dat){
url <- paste0("https://etp.taipower.com.tw/api/infoboard/settle_value/query?startDate=",
as.character(i))
dfi <- read_html(url) %>%
html_nodes("p") %>%
html_text %>%
fromJSON
dfi <- dfi$data
dfi <- dfi %>%
mutate(
datetime = ymd_hm(paste0(tranDate, " ", tranHour)))
dfi <- dfi %>% select(var)
df <- rbind(df, dfi)
}
最後用nrow觀察資料的筆數,並且用head()查看查詢的結果。
nrow(df)
## [1] 10680
head(df)
## datetime srBid srBidQse srPrice supBid supBidQse supPrice
## 1 2021-11-16 00:00:00 376.0 1 400 869.7 0 350
## 2 2021-11-16 01:00:00 346.0 1 400 823.1 0 350
## 3 2021-11-16 02:00:00 254.0 1 400 809.4 0 350
## 4 2021-11-16 03:00:00 363.0 1 400 759.3 0 350
## 5 2021-11-16 04:00:00 346.0 1 400 739.9 0 350
## 6 2021-11-16 05:00:00 361.2 1 400 844.5 0 350
在取得資料後,我們希望總得標容量以及月平均價格,而平均價格為每小時價格的加權平均數,以每小時得標容量為權重。
我們使用mutate來新增變數,Quant為總容量,計算方式為得標容量(國營)加上得標容量(民營)。由於我們想計算月平均,因此我們需要先將所有資料根據月份分組。format可以更改物件的格式,如下表示將日期時間格式改為年-月格式。%Y為年,而%m為月。str()顯示物件的架構,若函數放入資料框,則回傳每個變數,可以看到最下方三個為剛剛新增的變數。
# sr: 即時備轉, sup: 補充備轉
# Bid: 得標容量(國營)(MW), BidQse: 得標容量(民營)(MW), Price: 結清價格(元 / MW·h)
# Quant = Bid + BidQse
df <- df %>% mutate(month = format(df$datetime, "%Y-%m"),
srQuant = srBid + srBidQse,
supQuant = supBid + supBidQse)
str(df)
## 'data.frame': 10680 obs. of 10 variables:
## $ datetime : POSIXct, format: "2021-11-16 00:00:00" "2021-11-16 01:00:00" ...
## $ srBid : num 376 346 254 363 346 ...
## $ srBidQse : num 1 1 1 1 1 1 1 1 1 1 ...
## $ srPrice : num 400 400 400 400 400 400 400 400 400 400 ...
## $ supBid : num 870 823 809 759 740 ...
## $ supBidQse: num 0 0 0 0 0 0 0 0 0 0 ...
## $ supPrice : num 350 350 350 350 350 350 350 350 350 350 ...
## $ month : chr "2021-11" "2021-11" "2021-11" "2021-11" ...
## $ srQuant : num 377 347 255 364 347 ...
## $ supQuant : num 870 823 809 759 740 ...
先使用group_by將所有資料根據month分組,接著將分組後的資料傳遞給summarise()函數,summarise會回傳計算後的統計值。weighted.mean()可以計算加權平均數,參數w指定為要使用的權重,na.rm則指定是否略過遺漏值,因為遺漏值無法被計算。w.avg.srPrice為即時備轉月加權平均價格,w.avg.supPrice為補充備轉月加權平均價格。
month_w_avg_price <- df %>%
group_by(month) %>%
summarise(
w.avg.srPrice = weighted.mean(srPrice, w = srQuant, na.rm = TRUE),
w.avg.supPrice = weighted.mean(supPrice, w = supQuant, na.rm = TRUE))
month_w_avg_price
## # A tibble: 16 × 3
## month w.avg.srPrice w.avg.supPrice
## <chr> <dbl> <dbl>
## 1 2021-11 400 350
## 2 2021-12 400. 349.
## 3 2022-01 400. 347.
## 4 2022-02 399. 347.
## 5 2022-03 398. 349.
## 6 2022-04 398. 349.
## 7 2022-05 398. 341.
## 8 2022-06 399. 301.
## 9 2022-07 399. 323.
## 10 2022-08 399. 328.
## 11 2022-09 381. 264.
## 12 2022-10 336. 246.
## 13 2022-11 363. 259.
## 14 2022-12 352. 248.
## 15 2023-01 341. 248.
## 16 2023-02 333. 251.
# mean without weight and advanced method
# df %>%
# group_by(month) %>%
# summarise(
# across(ends_with("Price"), mean, na.rm = TRUE, .names = "avg.{.col}"))
setwd指定我們要儲存資料的資料夾位置。
最後我們需要將整個資料框和計算結果合併成一個excel檔案,並且存於不同的活頁簿,剛好list格式可以方便對應到excel的輸出形式。我們在一個list中建立兩個元素,一個是名為歷史結清價格與交易量的df物件,另一個是名為月均價的month_w_avg_price物件。最後使用write.xlsx將這個list匯出為excel檔案,指定檔案名為”歷史結清價格與交易量.xlsx”。
接下來就可以到資料夾內查看輸出的excel檔案。
setwd("~/Desktop/R/CIER/電力交易平台")
output <- list(歷史結清價格與交易量 = df, 月均價 = month_w_avg_price)
str(output)
## List of 2
## $ 歷史結清價格與交易量:'data.frame': 10680 obs. of 10 variables:
## ..$ datetime : POSIXct[1:10680], format: "2021-11-16 00:00:00" "2021-11-16 01:00:00" ...
## ..$ srBid : num [1:10680] 376 346 254 363 346 ...
## ..$ srBidQse : num [1:10680] 1 1 1 1 1 1 1 1 1 1 ...
## ..$ srPrice : num [1:10680] 400 400 400 400 400 400 400 400 400 400 ...
## ..$ supBid : num [1:10680] 870 823 809 759 740 ...
## ..$ supBidQse: num [1:10680] 0 0 0 0 0 0 0 0 0 0 ...
## ..$ supPrice : num [1:10680] 350 350 350 350 350 350 350 350 350 350 ...
## ..$ month : chr [1:10680] "2021-11" "2021-11" "2021-11" "2021-11" ...
## ..$ srQuant : num [1:10680] 377 347 255 364 347 ...
## ..$ supQuant : num [1:10680] 870 823 809 759 740 ...
## $ 月均價 : tibble [16 × 3] (S3: tbl_df/tbl/data.frame)
## ..$ month : chr [1:16] "2021-11" "2021-12" "2022-01" "2022-02" ...
## ..$ w.avg.srPrice : num [1:16] 400 400 400 399 398 ...
## ..$ w.avg.supPrice: num [1:16] 350 349 347 347 349 ...
write.xlsx(output, file = "歷史結清價格與交易量.xlsx")