今回は東京電力の消費電力量をC#で分析してみることにします。消費電力量はここからダウンロードできます。スクレーピングというヤバいことをする必要はありません。
過去の電力使用実績データのダウンロード|でんき予報の解説|東京電力ホールディングス株式会社
ダウンロードしたら適当なフォルダをつくって保存しておきましょう。ここではダウンロードしたファイルを実行ファイルと同じフォルダに保存しています。
以下は保存しているCSVファイルのリストを取得するメソッドです。ファイルはたしかに存在するという前提で作成しているのでファイルが存在しない場合はその旨メッセージボックスが表示されますが、エラー時の処理はしていません(超テキトー。本当はダメです)。
ClosedXMLを使うのでNuGetでインストールしておいてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
using System.IO; using ClosedXML.Excel; public partial class Form1 : Form { List<string> GetCsvPaths() { List<string> paths = new List<string>(); paths.Add(Application.StartupPath + "\\juyo-2017.csv"); paths.Add(Application.StartupPath + "\\juyo-2018.csv"); paths.Add(Application.StartupPath + "\\juyo-2019.csv"); paths.Add(Application.StartupPath + "\\juyo-2020.csv"); // 念の為チェック チェックは通る前提 foreach (string path in paths) { if (!File.Exists(path)) MessageBox.Show(path + "は存在しません"); } return paths; } } |
ダウンロードしたCSVファイルは以下のような構造になっているので最初の3行は捨ててあとは以下に示すDataオブジェクトのリストとして取得できるようにしておきます。
1 2 3 4 5 6 7 8 |
2019/1/1 18:10 UPDATE DATE,TIME,実績(万kW) 2017/1/1,0:00,2783 2017/1/1,1:00,2634 2017/1/1,2:00,2520 2017/1/1,3:00,2438 2017/1/1,4:00,2389 |
これがDataクラスです。2017/1/1,0:00,2783のような文字列を渡すと、年、月、日、時刻、消費電力(KW)に分解してDataクラスのなかに格納します。2017/1/1,0:00,2783であれば “/”, “,”, “:” で分割すれば必要なデータを取得できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
public class Data { public Data(string str) { string[] vs = str.Split(new string[] { "/", ",", ":" }, StringSplitOptions.None); Year = int.Parse(vs[0]); Month = int.Parse(vs[1]); Day = int.Parse(vs[2]); Hour = int.Parse(vs[3]); ElectricPowerKW = int.Parse(vs[5]); } public int Year { get; private set; } public int Month { get; private set; } public int Day { get; private set; } public int Hour { get; private set; } public int ElectricPowerKW { get; private set; } } |
これはCSVファイルからDataオブジェクトのリストを生成して返すメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
public partial class Form1 : Form { List<Data> GetDatasFromCsv() { List<string> paths = GetCsvPaths(); List<Data> datas = new List<Data>(); foreach (string path in paths) { StreamReader sr = new StreamReader(path); int lineCount = 0; while (true) { lineCount++; string line = sr.ReadLine(); if (line == null) break; // 最初の3行は捨てる if (lineCount > 3) { datas.Add(new Data(line)); } } } return datas; } } |
これは1時間おきに記録されている電力使用実績をそのまま表にしただけです。
実行結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
public partial class Form1 : Form { private void button1_Click(object sender, EventArgs e) { List<Data> datas = GetDatasFromCsv(); SaveExcelFile1(@"Excelファイルを保存するパス", datas); } void SaveExcelFile1(string excelPath, List<Data> datas) { using (XLWorkbook workbook = new XLWorkbook()) { IXLWorksheet worksheet = workbook.Worksheets.Add("シート1"); int row = 1; worksheet.Cell(row, "A").Value = "年"; worksheet.Cell(row, "B").Value = "月"; worksheet.Cell(row, "C").Value = "日"; worksheet.Cell(row, "D").Value = "時刻"; worksheet.Cell(row, "E").Value = "電力使用実績"; foreach (Data data in datas) { row++; worksheet.Cell(row, "A").Value = data.Year; worksheet.Cell(row, "B").Value = data.Month; worksheet.Cell(row, "C").Value = data.Day; worksheet.Cell(row, "D").Value = data.Hour; worksheet.Cell(row, "E").Value = data.ElectricPowerKW; } workbook.SaveAs(excelPath); } } } |
先程は1時間おきに記録されている電力使用実績をそのまま表にしただけであり、データとして面白くありません。そこで各月の電力使用実績を表にします。これで電力使用量が多い月とそうでない月がわかります。
それから最大値と最小値が大きく異なる月があるかもしれません。そこでそれもわかるようにしました。
実行結果
まずはExcelで書き込むデータを格納するクラスをつくります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
public class Data2 { public Data2(int year, int month, List<int> electricPowers) { Year = year; Month = month; ElectricPowers = electricPowers; } public int Year { get; private set; } public int Month { get; private set; } List<int> ElectricPowers { get; set; } public int TotalPower { get { return ElectricPowers.Sum(); } } public int MaxPower { get { return ElectricPowers.Max(); } } public int MinPower { get { return ElectricPowers.Min(); } } } |
まずDataオブジェクトのリストを取得してから、Data.YearとData.Monthが同じもののグループ化します。そしてここからData2オブジェクトのリストを作成し、ファイルとして書き込みます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
public partial class Form1 : Form { private void button2_Click(object sender, EventArgs e) { List<Data> datas = GetDatasFromCsv(); var query = datas.GroupBy(x => new { Year = x.Year, Month = x.Month, }); List<Data2> data2s = new List<Data2>(); foreach (var group in query) { var key = group.Key; List<int> electricPowers = group.Select(x => x.ElectricPowerKW).ToList(); data2s.Add(new Data2(key.Year, key.Month, electricPowers)); } SaveExcelFile2(@"Excelファイルを保存するパス", data2s); } void SaveExcelFile2(string excelPath, List<Data2> datas) { using (XLWorkbook workbook = new XLWorkbook()) { IXLWorksheet worksheet = workbook.Worksheets.Add("シート1"); int row = 1; worksheet.Cell(row, "A").Value = "年"; worksheet.Cell(row, "B").Value = "月"; worksheet.Cell(row, "C").Value = "電力使用実績"; worksheet.Cell(row, "D").Value = "最大値"; worksheet.Cell(row, "E").Value = "最小値"; worksheet.Cell(row, "F").Value = "最大と最小の差"; foreach (Data2 data in datas) { row++; worksheet.Cell(row, "A").Value = data.Year; worksheet.Cell(row, "B").Value = data.Month; // カンマ区切り worksheet.Cell(row, "C").SetValue(data.TotalPower).Style.NumberFormat.SetFormat("#,##0"); worksheet.Cell(row, "D").Value = data.MaxPower; worksheet.Cell(row, "E").Value = data.MinPower; worksheet.Cell(row, "F").Value = data.MaxPower - data.MinPower; } workbook.SaveAs(excelPath); } } } |
それから時間帯によっても消費電力は変わってきます。昼は工場で大量に電気を消費すると予想できます。ただ一般家庭では夏と冬では消費電力が大きくなる時間帯は違ってくるかもしれません。そこで月と時間帯のふたつに注目して表をつくります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public class Data3 { public Data3(int year, int month, List<int> electricPowers) { Year = year; Month = month; ElectricPowers = electricPowers; } public int Year { get; private set; } public int Month { get; private set; } public List<int> ElectricPowers { get; set; } } |
月日でグループ化し、さらに時刻でグループ化しています。そして時刻でグループ化されたDataオブジェクトからData.ElectricPowerKWの平均値を求めます。そしてこれをExcelファイルとして保存します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
public partial class Form1 : Form { private void button3_Click(object sender, EventArgs e) { List<Data> datas = GetDatasFromCsv(); SaveExcelFile1(@"d:\1.xlsx", datas); List<Data3> data3s = new List<Data3>(); // 月日でグループ化 var query = datas.GroupBy(x => new { Year = x.Year, Month = x.Month, }); foreach (var group in query) { var key = group.Key; // 時刻でグループ化 var query2 = group.GroupBy(x => x.Hour); List<int> electricPowers = new List<int>(); foreach (var group2 in query2) { electricPowers.Add((int)group2.Average(x => x.ElectricPowerKW)); } data3s.Add(new Data3(key.Year, key.Month, electricPowers)); } SaveExcelFile3(@"d:\3.xlsx", data3s); } void SaveExcelFile3(string excelPath, List<Data3> datas) { using (XLWorkbook workbook = new XLWorkbook()) { IXLWorksheet worksheet = workbook.Worksheets.Add("シート1"); int row = 1; worksheet.Cell(row, "A").Value = "年"; worksheet.Cell(row, "B").Value = "月"; for (int i = 0; i < 24; i++) { worksheet.Cell(row, i+3).SetValue<string>(String.Format("{0}:00", i)); } foreach (Data3 data in datas) { row++; worksheet.Cell(row, "A").Value = data.Year; worksheet.Cell(row, "B").Value = data.Month; int colum = 3; foreach (int electricPower in data.ElectricPowers) { worksheet.Cell(row, colum).Value = electricPower; colum++; } } workbook.SaveAs(excelPath); } } } |