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