chore: add weather pipeline example
This commit is contained in:
65
examples/02_demonstration/weather/custom_types.midas
Normal file
65
examples/02_demonstration/weather/custom_types.midas
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
predicate in_range(min: float, max: float)(v: float) = min <= v & v <= max
|
||||||
|
predicate is_percentage = in_range(0.0, 100.0)
|
||||||
|
|
||||||
|
type Celsius = float
|
||||||
|
type Kelvin = float where _ >= 0
|
||||||
|
type Hectopascal = float
|
||||||
|
|
||||||
|
type Temperature = Celsius where in_range(-30.0, 100.0)
|
||||||
|
type Pressure = Hectopascal where in_range(800.0, 1100.0)(_)
|
||||||
|
type Humidity = float where is_percentage(_)
|
||||||
|
type HeatIndex = float
|
||||||
|
|
||||||
|
type StationID = str where len(_) == 3 & _.isupper()
|
||||||
|
|
||||||
|
type Mean[T <: float] = float
|
||||||
|
|
||||||
|
extend Celsius {
|
||||||
|
def __add__: fn(Celsius, /) -> Celsius
|
||||||
|
def __sub__: fn(Celsius, /) -> Celsius
|
||||||
|
}
|
||||||
|
|
||||||
|
extend Kelvin {
|
||||||
|
def __add__: fn(Kelvin, /) -> Kelvin
|
||||||
|
}
|
||||||
|
|
||||||
|
extend Hectopascal {
|
||||||
|
def __add__: fn(Hectopascal, /) -> Hectopascal
|
||||||
|
def __sub__: fn(Hectopascal, /) -> Hectopascal
|
||||||
|
}
|
||||||
|
|
||||||
|
alias RawData = Frame[
|
||||||
|
station_id: str,
|
||||||
|
timestamp: str,
|
||||||
|
temperature: float,
|
||||||
|
pressure: float,
|
||||||
|
humidity: float,
|
||||||
|
]
|
||||||
|
|
||||||
|
alias Data = Frame[
|
||||||
|
station_id: StationID,
|
||||||
|
timestamp: object,
|
||||||
|
temperature: Temperature,
|
||||||
|
pressure: Pressure,
|
||||||
|
humidity: Humidity,
|
||||||
|
]
|
||||||
|
|
||||||
|
alias DataWithHI = Frame[
|
||||||
|
station_id: StationID,
|
||||||
|
timestamp: object,
|
||||||
|
temperature: Temperature,
|
||||||
|
pressure: Pressure,
|
||||||
|
humidity: Humidity,
|
||||||
|
heat_index: HeatIndex,
|
||||||
|
]
|
||||||
|
|
||||||
|
alias DailyAverages = Frame[
|
||||||
|
timestamp: object,
|
||||||
|
temperature: Mean[Temperature],
|
||||||
|
pressure: Mean[Pressure],
|
||||||
|
humidity: Mean[Humidity],
|
||||||
|
heat_index: Mean[HeatIndex],
|
||||||
|
]
|
||||||
|
|
||||||
|
predicate limit_amplitude(max_amp: float)(ls: list[float]) = max(ls) - min(ls) <= max_amp
|
||||||
|
type LowAmplitudeWave = list[float where _ >= 1] where limit_amplitude(10)(_)
|
||||||
43
examples/02_demonstration/weather/gen_data.py
Normal file
43
examples/02_demonstration/weather/gen_data.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import datetime
|
||||||
|
import random
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
stations = ["SIO", "AIG", "ZER"]
|
||||||
|
|
||||||
|
start_ts = datetime.datetime(2026, 1, 1)
|
||||||
|
end_ts = datetime.datetime(2027, 1, 1)
|
||||||
|
delta = end_ts - start_ts
|
||||||
|
|
||||||
|
min_temp, max_temp = -30.0, 100.0
|
||||||
|
min_pres, max_pres = 800.0, 1100.0
|
||||||
|
min_hum, max_hum = 0.0, 1.0
|
||||||
|
|
||||||
|
N = 3000
|
||||||
|
|
||||||
|
rows: list[tuple[str, datetime.datetime, float, float, float]] = []
|
||||||
|
|
||||||
|
for _ in range(N):
|
||||||
|
ts = random.random() * delta + start_ts
|
||||||
|
rows.append(
|
||||||
|
(
|
||||||
|
random.choice(stations),
|
||||||
|
ts,
|
||||||
|
random.random() * (max_temp - min_temp) + min_temp,
|
||||||
|
random.random() * (max_pres - min_pres) + min_pres,
|
||||||
|
random.random() * (max_hum - min_hum) + min_hum,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
df = pd.DataFrame(
|
||||||
|
rows,
|
||||||
|
columns=[
|
||||||
|
"station_id",
|
||||||
|
"timestamp",
|
||||||
|
"temperature",
|
||||||
|
"pressure",
|
||||||
|
"humidity",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
df = df.sort_values(by=["timestamp", "station_id"])
|
||||||
|
df.to_csv("data.csv", index=False)
|
||||||
69
examples/02_demonstration/weather/pipeline.py
Normal file
69
examples/02_demonstration/weather/pipeline.py
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import pandas as pd
|
||||||
|
from custom_types import DailyAverages, Data, DataWithHI, HeatIndex, RawData
|
||||||
|
|
||||||
|
from midas.typing import Column, cast, unsafe_cast
|
||||||
|
|
||||||
|
|
||||||
|
def load_data(path: Path) -> RawData:
|
||||||
|
return cast(RawData, pd.read_csv(path))
|
||||||
|
|
||||||
|
|
||||||
|
def convert_data(raw_df: RawData) -> Data:
|
||||||
|
new_df = raw_df.copy()
|
||||||
|
new_df["timestamp"] = cast(
|
||||||
|
Column[object],
|
||||||
|
pd.to_datetime(new_df["timestamp"]),
|
||||||
|
)
|
||||||
|
return cast(Data, new_df)
|
||||||
|
|
||||||
|
|
||||||
|
def compute_heat_index(df: Data):
|
||||||
|
df["heat_index"] = cast(
|
||||||
|
Column[HeatIndex],
|
||||||
|
(
|
||||||
|
df["temperature"] * 2.0
|
||||||
|
+ df["humidity"] * 10.0
|
||||||
|
- df["temperature"] * df["humidity"] * 0.2
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return df
|
||||||
|
|
||||||
|
|
||||||
|
def daily_avg(df: DataWithHI):
|
||||||
|
return cast(
|
||||||
|
DailyAverages,
|
||||||
|
df.groupby(
|
||||||
|
by=[
|
||||||
|
df["station_id"],
|
||||||
|
df["timestamp"].dt.day.rename("day"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.mean()
|
||||||
|
.sort_values(by="timestamp"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def plot(df: DailyAverages):
|
||||||
|
stations = unsafe_cast(list[str], list(df.index.get_level_values(0).unique()))
|
||||||
|
for station in stations:
|
||||||
|
sub_df = unsafe_cast(DailyAverages, df.loc[station])
|
||||||
|
# plt.plot(sub_df["timestamp"], sub_df["temperature"])
|
||||||
|
plt.plot(sub_df["timestamp"], sub_df["heat_index"])
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
raw_df: RawData = load_data(Path("data.csv"))
|
||||||
|
df: Data = convert_data(raw_df)
|
||||||
|
|
||||||
|
with_hi = compute_heat_index(df)
|
||||||
|
dailies = daily_avg(with_hi)
|
||||||
|
print(dailies)
|
||||||
|
plot(dailies)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user