
一、從三體運動到太陽黑子變化預(yù)測
1、前言
太陽黑子是太陽光球?qū)由习l(fā)生的太陽活動現(xiàn)象,通常成群出現(xiàn)。預(yù)測太陽黑子變化是空間氣象研究中最活躍的領(lǐng)域之一。
太陽黑子觀測持續(xù)時間很長。長時間的數(shù)據(jù)積累有利于挖掘太陽黑子變化的規(guī)律。長期觀測顯示,太陽黑子數(shù)及面積變化呈現(xiàn)出明顯的周期 性,且周期呈現(xiàn)不規(guī)則性,大致范圍在 9 ~ 13 a , 平均周期約為 11 a,太陽黑子數(shù)及面積變化的峰值不恒定。
最新數(shù)據(jù)顯示,近些年來太陽黑子數(shù)和面積有明顯的下降趨勢。

鑒于太陽黑子活動強烈程度對地球有著深刻的影響,因此探測太陽黑子活動就顯得尤為重要?;谖锢韺W(xué)模型(如動力模型)和統(tǒng)計學(xué)模型(如自回歸滑動平均)已被廣泛應(yīng)用于探測太陽黑子活動。為了更高效地捕捉太陽黑子時間序列中存在的非線性關(guān)系,機器學(xué)習(xí)方法被引入。
值得一提的是,機器學(xué)習(xí)中的神經(jīng)網(wǎng)絡(luò)更擅長挖掘數(shù)據(jù)中的非線性關(guān)系。
因此,本文將介紹如何使用時序數(shù)據(jù)庫 CnosDB 存儲太陽黑子變化數(shù)據(jù),并進一步使用TensorFlow實現(xiàn)1DConv+LSTM 網(wǎng)絡(luò)來預(yù)測太陽黑子數(shù)量變化。
2、太陽黑子變化觀測數(shù)據(jù)集簡介
本文使用的太陽黑子數(shù)據(jù)集是由SILSO 網(wǎng)站發(fā)布2.0版本(WDC-SILSO, Royal Observatory of Belgium, Brussels, http://sidc.be/silso/datafiles)。

我們主要分析和探索:1749至2023年,月均太陽黑子數(shù)(monthly mean sunspot number,MSSN)變化情況。
二、數(shù)據(jù)導(dǎo)入
將 MSSN 數(shù)據(jù) csv 格式文件 SN_m_tot_V2.0.csv (https://www.sidc.be/silso/infosnmtot) 下載到本地。
以下是官方提供的 CSV 文件描述:
Filename: SN_m_tot_V2.0.csv
Format: Comma Separated values (adapted for import in spreadsheets)
The separator is the semicolon ';'.
Contents:
Column 1-2: Gregorian calendar date
- Year
- Month
Column 3: Date in fraction of year.
Column 4: Monthly mean total sunspot number.
Column 5: Monthly mean standard deviation of the input sunspot numbers.
Column 6: Number of observations used to compute the monthly mean total sunspot number.
Column 7: Definitive/provisional marker. '1' indicates that the value is definitive. '0' indicates that the value is still provisional.
我們使用 pandas 進行文件加載和預(yù)覽:
import pandas as pd
df = pd.read_csv("SN_m_tot_V2.0.csv", sep=";", header=None)
df.columns = ["year", "month", "date_fraction", "mssn", "standard_deviation", "observations", "marker"]
# convert year and month to strings
df["year"] = df["year"].astype(str)
df["month"] = df["month"].astype(str)
# concatenate year and month
df["date"] = df["year"] + "-" + df["month"]
df.head()

import matplotlib.pyplot as plt
df["Date"] = pd.to_datetime(df["date"], format="%Y-%m")
plt.plot(df["Date"], df["mssn"])
plt.xlabel("Date")
plt.ylabel("MSSN")
plt.title("Sunspot Activity Over Time")
plt.show()

1、使用時序數(shù)據(jù)庫 CnosDB 存儲 MSSN 數(shù)據(jù)
CnosDB(An Open Source Distributed Time Series Database with high performance, high compression ratio and high usability.)。
- Official Website: ?http://www.cnosdb.com?
- Github Repo: ?https://github.com/cnosdb/cnosdb?
(注:本文假設(shè)你已具備 CnosDB 安裝部署和基本使用能力,相關(guān)文檔詳見 ?https://docs.cnosdb.com/?)。
在命令行中使用 Docker 啟動 CnosDB 數(shù)據(jù)庫服務(wù),并進入容器使用 CnosDB CLI 工具直接訪問 CnosDB:
(base) root@ecs-django-dev:~# docker run --restart=always --name cnosdb -d --env cpu=2 --env memory=4 -p 31007:31007 cnosdb/cnosdb:v2.0.2.1-beta
(base) root@ecs-django-dev:~# docker exec -it cnosdb sh sh
# cnosdb-cli
CnosDB CLI v2.0.0
Input arguments: Args { host: "0.0.0.0", port: 31007, user: "cnosdb", password: None, database: "public", target_partitions: None, data_path: None, file: [], rc: None, format: Table, quiet: false }
為了簡化分析,我們只需存儲數(shù)據(jù)集中觀測時間和太陽黑子數(shù)。因此,我們將年(Col 0)和月(Col 1)拼接作為觀測時間(date, 字符串類型),月均太陽黑子數(shù)(Col 3)可以不作處理直接存儲。
我們可以在 CnosDB CLI 中使用 SQL 創(chuàng)建一張名為 sunspot 數(shù)據(jù)表,以用于存儲 MSSN 數(shù)據(jù)集。
public ? CREATE TABLE sunspot (
date STRING,
mssn DOUBLE,
);
Query took 0.002 seconds.
public ? SHOW TABLES;
+---------+
| Table |
+---------+
| sunspot |
+---------+
Query took 0.001 seconds.
public ? SELECT * FROM sunspot;
+------+------+------+
| time | date | mssn |
+------+------+------+
+------+------+------+
Query took 0.002 seconds.
2、使用 CnosDB Python Connector 連接和讀寫 CnosDB 數(shù)據(jù)庫
Github Repo: https://github.com/cnosdb/cnosdb-client-python?。
# 安裝 Python Connector
pip install -U cnos-connector
from cnosdb_connector import connect
conn = connect(url="http://127.0.0.1:31001/", user="root", password="")
cursor = conn.cursor()
如果不習(xí)慣使用 CnosDB CLI,我們也可以直接使用 Python Connector 創(chuàng)建數(shù)據(jù)表。
# 創(chuàng)建 tf_demo database
conn.create_database("tf_demo")
# 使用 tf_demo database
conn.switch_database("tf_demo")
print(conn.list_database())
cursor.execute("CREATE TABLE sunspot (date STRING, mssn DOUBLE,);")
print(conn.list_table())
輸出如下,其中包括 CnosDB 默認的 Database。
[{'Database': 'tf_demo'}, {'Database': 'usage_schema'}, {'Database': 'public'}]
[{'Table': 'sunspot'}]
將之前 pandas 的 dataframe 寫入 CnosDB。
### df 為pandas的dataframe,"sunspot"為CnosDB中的表名,['date', 'mssn']為需要寫入的列的名字
### 如果寫入的列不包含時間列,將會根據(jù)當(dāng)前時間自動生成
conn.write_dataframe(df, "sunspot", ['date', 'mssn'])
三、讀取數(shù)據(jù)
參考論文:程術(shù), 石耀霖, 張懷. 基于神經(jīng)網(wǎng)絡(luò)預(yù)測太陽黑子變化 (2022)。
鏈接: ?http://journal.ucas.ac.cn/CN/10.7523/j.ucas.2021?.0068

使用 CnosDB 讀取數(shù)據(jù)
df = pd.read_sql("select * from sunspot;", conn)
print(df.head())

四、將數(shù)據(jù)集劃分為訓(xùn)練集和測試集
import numpy as np
# Convert the data values to numpy for better and faster processing
time_index = np.array(df['date'])
data = np.array(df['mssn'])
# ratio to split the data
SPLIT_RATIO = 0.8
# Dividing into train-test split
split_index = int(SPLIT_RATIO * data.shape[0])
# Train-Test Split
train_data = data[:split_index]
train_time = time_index[:split_index]
test_data = data[split_index:]
test_time = time_index[split_index:]
使用滑動窗口法構(gòu)造訓(xùn)練數(shù)據(jù)

import tensorflow as tf
## required parameters
WINDOW_SIZE = 60
BATCH_SIZE = 32
SHUFFLE_BUFFER = 1000
## function to create the input features
def ts_data_generator(data, window_size, batch_size, shuffle_buffer):
'''
Utility function for time series data generation in batches
'''
ts_data = tf.data.Dataset.from_tensor_slices(data)
ts_data = ts_data.window(window_size + 1, shift=1, drop_remainder=True)
ts_data = ts_data.flat_map(lambda window: window.batch(window_size + 1))
ts_data = ts_data.shuffle(shuffle_buffer).map(lambda window: (window[:-1], window[-1]))
ts_data = ts_data.batch(batch_size).prefetch(1)
return ts_data# Expanding data into tensors
# Expanding data into tensors
tensor_train_data = tf.expand_dims(train_data, axis=-1)
tensor_test_data = tf.expand_dims(test_data, axis=-1)
## generate input and output features for training and testing set
tensor_train_dataset = ts_data_generator(tensor_train_data, WINDOW_SIZE, BATCH_SIZE, SHUFFLE_BUFFER)
tensor_test_dataset = ts_data_generator(tensor_test_data, WINDOW_SIZE, BATCH_SIZE, SHUFFLE_BUFFER)
五、定義 1DConv+LSTM 神經(jīng)網(wǎng)絡(luò)模型
model = tf.keras.models.Sequential([
tf.keras.layers.Conv1D(filters=128, kernel_size=3, strides=1, input_shape=[None, 1]),
tf.keras.layers.MaxPool1D(pool_size=2, strides=1),
tf.keras.layers.LSTM(128, return_sequences=True),
tf.keras.layers.LSTM(64, return_sequences=True),
tf.keras.layers.Dense(132, activatinotallow="relu"),
tf.keras.layers.Dense(1)])
## compile neural network model
optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3)
model.compile(loss="mse",
optimizer=optimizer,
metrics=["mae"])
## training neural network model
history = model.fit(tensor_train_dataset, epochs=20, validation_data=tensor_test_dataset)

# summarize history for loss
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()

六、使用訓(xùn)練好的模型預(yù)測 MSSN
def model_forecast(model, data, window_size):
ds = tf.data.Dataset.from_tensor_slices(data)
ds = ds.window(window_size, shift=1, drop_remainder=True)
ds = ds.flat_map(lambda w: w.batch(window_size))
ds = ds.batch(32).prefetch(1)
forecast = model.predict(ds)
return forecast
rnn_forecast = model_forecast(model, data[..., np.newaxis], WINDOW_SIZE)
rnn_forecast = rnn_forecast[split_index - WINDOW_SIZE:-1, -1, 0]
# Overall Error
error = tf.keras.metrics.mean_absolute_error(test_data, rnn_forecast).numpy()
print(error)
101/101 [==============================] - 2s 18ms/step
24.676455
七、與真實值對比的可視化結(jié)果
plt.plot(test_data)
plt.plot(rnn_forecast)
plt.title('MSSN Forecast')
plt.ylabel('MSSN')
plt.xlabel('Month')
plt.legend(['Ground Truth', 'Predictions'], loc='upper right')
plt.show()

產(chǎn)品相關(guān)文檔:
1. CnosDB快速上手指南: ?https://docs.cnosdb.com?
2. CnosDB官網(wǎng): ?https://www.cnosdb.com?
3. CnosDB GitHub倉庫:
?https://github.com/cnosdb/cnosdb?
參考文獻:
?程術(shù), 石耀霖, 張懷. 基于神經(jīng)網(wǎng)絡(luò)預(yù)測太陽黑子變化(2022) http://journal.ucas.ac.cn/CN/10.7523/j.ucas.2021.0068
今天的分享就到這里,謝謝大家。?