Giriş

Bu döküman enerji sektöründe analist olarak çalışmaya başlayan veya enerji sektörü için analiz yapmak isteyenlere yönelik olarak R yardımı ile KÜPST cezalarının nasıl hesaplanabileceğini göstermek için hazırlanmıştır. Dökümanda kullanılan veri setleri EPİAŞ Şeffaflık Platformu’ndan alınmıştır.

Bu dökümanda kullanılan kodlar hakkında daha fazla bilgi edinmek ve R’da dplyr, ggplot2 ve lubridate gibi paketlerin nasıl kullanabileceğini daha iyi anlamak için R İLE ENERJİ PİYASASI VERİ ANALİZİ EL KİTABI’nı inceleyebilirsiniz. R hakkında kendinizi yeterli hissetmiyorsanız bu dökümanı incelemeden önce yukarıdaki kitabı incelemenizi şiddetle tavsiye ediyoruz.

Gerekli Paketlerin Elde Edilmesi ve Veri Setlerinin İndirilmesi

Bu dökümanda gerekli veri manipülasyonları için dplyr, tarih ve saatlerle ilgili veri manipülasyonları için lubridate paketleri kullanılmıştır. Bu paketlerin indirilip yüklenmesi için aşağıdaki adımlar izlenebilir:

1. Gerekli Paketleri İndirmek İçin

install.packages("dplyr")
install.packages("lubridate")

2. Gerekli Paketleri Yüklemek İçin

library(dplyr)
library(lubridate)

Bu dökümanda 2019 yılı PTF (Piyasa Takas Fiyatı), SMF (Sistem Marjinal Fiyatı), GZÜ (Gerçek Zamanlı Üretim) ve KUDÜP (Kesinleştirilmiş Uzlaştırma Dönemi Üretim Planı) değerleri ve örnek santral olarak Bergama RES Enerji Üretim AŞ. ve bu şirkete bağlı Aliağa RES (Rüzgar Enerji Santrali) seçilerek elde edilmiş veri setleri kullanılmıştır.

Bu değişkenlerin ne anlama geldiğinden kısaca bahsetmek gerekirse:

Bu veri setlerini indirmek için aşağıdaki yollar izlenebilir:

1. PTF - SMF Verisini İndirmek İçin

ptfsmf <- readRDS(url("https://github.com/barandogru/kupst_cezasi_hesaplama/blob/master/ptfsmf.RDS?raw=true"))

2. KUDÜP Verisini İndirmek İçin

kudup <- readRDS(url("https://github.com/barandogru/kupst_cezasi_hesaplama/blob/master/kudup.RDS?raw=true"))

3. GZÜ Verisini İndirmek İçin

gzu <- readRDS(url("https://github.com/barandogru/kupst_cezasi_hesaplama/blob/master/gzu.RDS?raw=true"))

Bu aşama başarıyla tamamlandığında bir sonraki bölüme geçilebilir.

Veri Manipülasyonları / Formatlamaları

Bu bölümde ham halde indirilen veri setlerinin nasıl doğru formatlara getirileceği anlatılacaktır. Bu aşamalar daha sonra bu veri setlerinin tek bir veri setinde toplanılabilmesi ve üzerinde çeşitli işlemlerin yapılabilmesi için gerekli işlemlerdir.

İlk olarak PTF - SMF verisi incelenecek olursa tablonun ilk haline göz atmak için,

ptfsmf
## # A tibble: 8,760 x 6
##    Tarih    PTF    SMF   `Pozitif Dengesizlik … `Negatif Dengesizlik… `SMF Yön` 
##    <chr>    <chr>  <chr> <chr>                  <chr>                 <chr>     
##  1 01.01.1… 100,38 5,00  4,85                   103,39                ↓Enerji F…
##  2 01.01.1… 96,72  95,04 92,19                  99,62                 ↓Enerji F…
##  3 01.01.1… 81,60  79,60 77,21                  84,05                 ↓Enerji F…
##  4 01.01.1… 38,58  0,00  0,00                   39,74                 ↓Enerji F…
##  5 01.01.1… 11,52  0,00  0,00                   11,87                 ↓Enerji F…
##  6 01.01.1… 11,14  0,00  0,00                   11,47                 ↓Enerji F…
##  7 01.01.1… 11,14  0,00  0,00                   11,47                 ↓Enerji F…
##  8 01.01.1… 24,37  0,00  0,00                   25,10                 ↓Enerji F…
##  9 01.01.1… 34,50  0,00  0,00                   35,53                 ↓Enerji F…
## 10 01.01.1… 45,21  0,00  0,00                   46,57                 ↓Enerji F…
## # … with 8,750 more rows

Gerekli değişikliklerin uygulamanmasını sağlayacak kodlar yazılırsa,

colnames(ptfsmf)[4] = "PDF"
colnames(ptfsmf)[5] = "NDF"
ptfsmf <- ptfsmf %>% mutate(Tarih_Yeni = as.POSIXct(ptfsmf$Tarih,format="%d.%m.%y %H:%M", "GMT")) %>%
  select(Tarih_Yeni, PTF, SMF) %>%
  rename(Tarih = Tarih_Yeni)
ptfsmf[,c(2:3)] <- lapply(ptfsmf[,c(2:3)],function(x) as.numeric(gsub(",", ".", gsub("\\.", "", x))))

Tablonun güncellenmiş haline göz atmak için,

ptfsmf
## # A tibble: 8,760 x 3
##    Tarih                 PTF   SMF
##    <dttm>              <dbl> <dbl>
##  1 2019-01-01 00:00:00 100.    5  
##  2 2019-01-01 01:00:00  96.7  95.0
##  3 2019-01-01 02:00:00  81.6  79.6
##  4 2019-01-01 03:00:00  38.6   0  
##  5 2019-01-01 04:00:00  11.5   0  
##  6 2019-01-01 05:00:00  11.1   0  
##  7 2019-01-01 06:00:00  11.1   0  
##  8 2019-01-01 07:00:00  24.4   0  
##  9 2019-01-01 08:00:00  34.5   0  
## 10 2019-01-01 09:00:00  45.2   0  
## # … with 8,750 more rows

Burada tarih formatı POSIXct formatı olarak değiştirildi, character formatında olan sayı değerleri numeric formatına güncellendi ve programın sayı değerlerini yanlış anlamasına sebep olan virgül ve nokta yerleştirmeleri düzenlendi.

Aynı işlemleri KUDÜP verisine uygulamadan önce KUDÜP veri setine göz atalım.

kudup
## # A tibble: 8,760 x 15
##    Tarih Saat  `Toplam (MWh)` `Doğal Gaz` Rüzgar Linyit `Taş Kömür`
##    <chr> <chr> <chr>          <chr>       <chr>  <chr>  <chr>      
##  1 01.0… 00:00 48,60          0,00        48,60  0,00   0,00       
##  2 01.0… 01:00 55,60          0,00        55,60  0,00   0,00       
##  3 01.0… 02:00 51,10          0,00        51,10  0,00   0,00       
##  4 01.0… 03:00 45,60          0,00        45,60  0,00   0,00       
##  5 01.0… 04:00 47,30          0,00        47,30  0,00   0,00       
##  6 01.0… 05:00 52,20          0,00        52,20  0,00   0,00       
##  7 01.0… 06:00 57,10          0,00        57,10  0,00   0,00       
##  8 01.0… 07:00 62,70          0,00        62,70  0,00   0,00       
##  9 01.0… 08:00 92,30          0,00        92,30  0,00   0,00       
## 10 01.0… 09:00 69,00          0,00        69,00  0,00   0,00       
## # … with 8,750 more rows, and 8 more variables: `İthal Kömür` <chr>, `Fuel
## #   Oil` <chr>, Jeotermal <chr>, Barajlı <chr>, Nafta <chr>, Biyokütle <chr>,
## #   Akarsu <chr>, Diğer <chr>

Görüleceği üzere bu döküman için gerekli olmayan birçok sütuna sahip. Bu sütunların kaldırılması ve yukarıda bahsedilen dönüşümlerin yapılması,

kudup <- kudup %>%
  select(Tarih, Saat, Rüzgar) %>%
  rename(KUDUP = Rüzgar) %>%
  mutate(Tarih_Yeni = as.POSIXct(paste(Tarih, Saat),format="%d.%m.%Y %H:%M", "GMT")) %>%
  select(Tarih_Yeni, KUDUP) %>%
  rename(Tarih = Tarih_Yeni)
kudup$KUDUP <- as.numeric(gsub(",", "\\.", kudup$KUDUP))

Tablonun son haline bakacak olursak,

kudup
## # A tibble: 8,760 x 2
##    Tarih               KUDUP
##    <dttm>              <dbl>
##  1 2019-01-01 00:00:00  48.6
##  2 2019-01-01 01:00:00  55.6
##  3 2019-01-01 02:00:00  51.1
##  4 2019-01-01 03:00:00  45.6
##  5 2019-01-01 04:00:00  47.3
##  6 2019-01-01 05:00:00  52.2
##  7 2019-01-01 06:00:00  57.1
##  8 2019-01-01 07:00:00  62.7
##  9 2019-01-01 08:00:00  92.3
## 10 2019-01-01 09:00:00  69  
## # … with 8,750 more rows

Son olarak da aynı işlemleri GZÜ veri setine uygulamadan önce veri setini inceleyecek olursak,

gzu
## # A tibble: 8,760 x 18
##    Tarih Saat  `Toplam (MWh)` `Doğal Gaz` Barajlı Linyit Akarsu `İthal Kömür`
##    <chr> <chr> <chr>          <chr>       <chr>   <chr>  <chr>  <chr>        
##  1 01.0… 00:00 1,62           0,00        0,00    0,00   0,00   0,00         
##  2 01.0… 01:00 0,51           0,00        0,00    0,00   0,00   0,00         
##  3 01.0… 02:00 2,47           0,00        0,00    0,00   0,00   0,00         
##  4 01.0… 03:00 4,27           0,00        0,00    0,00   0,00   0,00         
##  5 01.0… 04:00 14,62          0,00        0,00    0,00   0,00   0,00         
##  6 01.0… 05:00 12,66          0,00        0,00    0,00   0,00   0,00         
##  7 01.0… 06:00 4,18           0,00        0,00    0,00   0,00   0,00         
##  8 01.0… 07:00 3,53           0,00        0,00    0,00   0,00   0,00         
##  9 01.0… 08:00 14,49          0,00        0,00    0,00   0,00   0,00         
## 10 01.0… 09:00 16,68          0,00        0,00    0,00   0,00   0,00         
## # … with 8,750 more rows, and 10 more variables: Rüzgar <chr>, Güneş <chr>,
## #   `Fuel Oil` <chr>, Jeotermal <chr>, `Asfaltit Kömür` <chr>, `Taş
## #   Kömür` <chr>, Biyokütle <chr>, Nafta <chr>, LNG <chr>, Uluslararası <chr>

Şimdi gerekli düzenlemeleri yapalım,

gzu <- gzu %>%
  select(Tarih, Saat, Rüzgar) %>%
  rename(GZU = Rüzgar) %>%
  mutate(Tarih_Yeni = as.POSIXct(paste(Tarih, Saat),format="%d.%m.%Y %H:%M", "GMT")) %>%
  select(Tarih_Yeni, GZU) %>%
  rename(Tarih = Tarih_Yeni)
gzu$GZU <- as.numeric(gsub(",", "\\.", gzu$GZU))

Tablonun son hali şu şekilde olacaktır,

gzu
## # A tibble: 8,760 x 2
##    Tarih                 GZU
##    <dttm>              <dbl>
##  1 2019-01-01 00:00:00  1.62
##  2 2019-01-01 01:00:00  0.51
##  3 2019-01-01 02:00:00  2.47
##  4 2019-01-01 03:00:00  4.27
##  5 2019-01-01 04:00:00 14.6 
##  6 2019-01-01 05:00:00 12.7 
##  7 2019-01-01 06:00:00  4.18
##  8 2019-01-01 07:00:00  3.53
##  9 2019-01-01 08:00:00 14.5 
## 10 2019-01-01 09:00:00 16.7 
## # … with 8,750 more rows

Son olarak, ortaya çıkan düzenlenmiş bu 3 tabloyu tek bir tabloda Tarih sütunu yardımıyla birleştirelim.

temp <- merge(x = gzu, y = kudup, by = "Tarih")
df <- merge(x = temp, y = ptfsmf, by = "Tarih")

Burada iki kere merge fonksiyonunun kullanılma sebebi bu fonksiyonun doğası gereği yalnızca iki tabloyu birleştirebilmesindendir. O nedenle iki ayrı birleştirme operasyonu yapılmış gibi düşünülebilir.

Tablonun son haline göz atacak olursak,

head(df, n=10)
##                  Tarih   GZU KUDUP    PTF   SMF
## 1  2019-01-01 00:00:00  1.62  48.6 100.38  5.00
## 2  2019-01-01 01:00:00  0.51  55.6  96.72 95.04
## 3  2019-01-01 02:00:00  2.47  51.1  81.60 79.60
## 4  2019-01-01 03:00:00  4.27  45.6  38.58  0.00
## 5  2019-01-01 04:00:00 14.62  47.3  11.52  0.00
## 6  2019-01-01 05:00:00 12.66  52.2  11.14  0.00
## 7  2019-01-01 06:00:00  4.18  57.1  11.14  0.00
## 8  2019-01-01 07:00:00  3.53  62.7  24.37  0.00
## 9  2019-01-01 08:00:00 14.49  92.3  34.50  0.00
## 10 2019-01-01 09:00:00 16.68  69.0  45.21  0.00

İstenilen her değişkeni aynı tabloda toplamayı ve bu değişkenleri gerekli formatlara getirmeyi başardık. KÜPST cezasının nasıl hesaplandığının anlatıldığı ve pratikte uygulandığı bir sonraki bölüme geçmeye hazırsınız.

KÜPST Cezası Hesaplanması

Uygulamaya geçmeden önce KÜPST cezasının teorik olarak nasıl hesaplandığından bahsetmek gerekmektedir. Yukarıda da bahsedildiği gibi KÜPST cezası saatlik KUDÜP ve gerçekleşen üretim miktarı arasındaki farkın belli bir toleransı geçmesiyle oluşur. KÜPST hesaplama aşamaları aşağıdaki gibidir.

\[ Tolerans = GZÜ / 10 \] \[ KÜPST = |GZÜ - KUDÜP| - Tolerans \] \[ Birim KÜPST = max(PTF, SMF)*0.03 \] \[ Toplam KÜPST = KÜPST*BirimKÜPST \]

Toplam KÜPST cezasının hesaplanma aşamaları anlatıldıktan sonra uygulamaya geçilebilir.

Gerekli kodlar şu şekildedir,

df <- df %>%
  mutate(Tolerans = GZU/10, KUPST = (abs(GZU - KUDUP) - Tolerans), 
         BirimKUPST = ifelse(PTF>SMF, PTF*0.03, SMF*0.03),
         KUPST_Cezasi = KUPST * BirimKUPST)

Tablonun son haline göz atacak olursak,

head(df, n=10)
##                  Tarih   GZU KUDUP    PTF   SMF Tolerans  KUPST BirimKUPST
## 1  2019-01-01 00:00:00  1.62  48.6 100.38  5.00    0.162 46.818     3.0114
## 2  2019-01-01 01:00:00  0.51  55.6  96.72 95.04    0.051 55.039     2.9016
## 3  2019-01-01 02:00:00  2.47  51.1  81.60 79.60    0.247 48.383     2.4480
## 4  2019-01-01 03:00:00  4.27  45.6  38.58  0.00    0.427 40.903     1.1574
## 5  2019-01-01 04:00:00 14.62  47.3  11.52  0.00    1.462 31.218     0.3456
## 6  2019-01-01 05:00:00 12.66  52.2  11.14  0.00    1.266 38.274     0.3342
## 7  2019-01-01 06:00:00  4.18  57.1  11.14  0.00    0.418 52.502     0.3342
## 8  2019-01-01 07:00:00  3.53  62.7  24.37  0.00    0.353 58.817     0.7311
## 9  2019-01-01 08:00:00 14.49  92.3  34.50  0.00    1.449 76.361     1.0350
## 10 2019-01-01 09:00:00 16.68  69.0  45.21  0.00    1.668 50.652     1.3563
##    KUPST_Cezasi
## 1     140.98773
## 2     159.70116
## 3     118.44158
## 4      47.34113
## 5      10.78894
## 6      12.79117
## 7      17.54617
## 8      43.00111
## 9      79.03364
## 10     68.69931

Burada yapılan işlemlerden kısaca bahsedecek olursak, öncelikle Tolerans adında bir sütun oluşturularak GZÜ değerinin 1/10’una eşitlendi. Sonra sırasıyla KÜPST ve Birim KÜPST değerleri yukarıda verilen denklemler çerçevesinde hesaplandı. En son olarak da toplam KÜPST cezası KUPST_Cezasi adında bir sütunda KUPST ve BirimKUPST değerlerinin çarpımıyla hesaplandı.

Sonuç

Bu dökümanda Rüzgar Enerji Santralleri (RES) için önemli bir dengesizlik cezası olan KÜPST cezasının nasıl hesaplanabileceği adım adım gösterilmeyi çalışılmıştır. Bu değerin Rüzgar Santralleri için önemli oldukça önemli olmasının nedeni, Rüzgar Santrallerinin genellikle dengeden sorumlu grup içerisinde olmalarından ve dengesizlik cezalarından fazla etkilenmeseler de KÜPST cezasından etkilenmelerinden kaynaklanmaktadır.

Herhangi bir sorun ya da öneri durumunda kitabın yazarına Baran Doğru hesabından ulaşabilirsiniz.

Kaynakça