単純移動平均で波形を描画する
一定期間ごとの平均を計算した単純移動平均の結果をC#で描画します。
以前の投稿と同様にコロナの感染者数を使用します。
https://www.mhlw.go.jp/stf/covid-19/open-data.html
5類感染症に移行したのでその時点で人数の更新が終わっていますね。
前の投稿も結構雑だなと思いますが、とりあえず流用します。
Windows11でVisual Studio 2022を使用しています。
Windows10のサポートが2025年10月に切れるので、Windows11に慣れるためにも早めに移行した方が良いかと思います。
実行結果と移動平均のメリット/デメリット
感染者数を5日/25日/75日の移動平均で描画した結果は画像のようになりました。
ちょっと見にくいので700~1000日目を表示したものが以下になります。
単純移動平均にすると大まかな流れを理解することができる場合があります。
5日平均と25日平均に着目すると、5日平均が25日平均を上回ると感染症数が増加傾向になり、逆に下回ると減少傾向となっています。
75日平均は実際の変動から遅れて変化しているため今回の場合だと大体の傾向を読み取れるだけとなります。
移動平均はフィルタとして使うこともできます。
感染症数をそのまま描画すると平日に比べ、土日の感染症数の数値が少ないためギザギザの波形となります。
移動平均により滑らかに変化するようになるため、フィルタとして使用できます。
ただし、平均する範囲が大きければ大きいほど反応が遅れるため注意が必要です。
また、計算自体が軽くないのでリアルタイムに描画する場合には不向きであり、この場合は1次遅れのローパスを使うのが良いと思われます。
コード
関数部分のみ抜粋です。
/// <summary>
/// 単純移動平均の結果を求める
/// </summary>
/// <param name="data">元となるデータリスト</param>
/// <param name="Length">平均化する対象の日数</param>
/// <returns>単純移動平均の結果リスト</returns>
private List<double> tanjun(List<int> data, int Length)
{
List<double> result = new List<double>();
// 平均化したい日数分のデータ
int[] ints = new int[Length];
// 更新するデータの位置
int count;
// 平均化したい日数分の最初のデータを反映する
for (count = 0; count < Length - 1; count++)
{
ints[count] = data[count];
}
// 平均化する
for (int i = Length - 1; i < data.Count; i++)
{
// 配列のデータを更新する(一番古いデータを更新)
ints[count] = data[i];
count++;
// 次の更新位置が配列数と同じなら0にする
if (count == Length)
{
count = 0;
}
// 配列の平均値をresultに追加する
result.Add(ints.Sum() / (double)Length);
}
return result;
}