Add worst high-traffic low-availability sites analysis and daily availability trends per RAT with SLA comparison
Browse files
apps/kpi_analysis/trafic_analysis.py
CHANGED
|
@@ -850,6 +850,158 @@ if st.button(" Run Analysis"):
|
|
| 850 |
st.subheader("Multi-RAT Availability by site (post-period)")
|
| 851 |
st.dataframe(multi_rat_df.round(2))
|
| 852 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 853 |
TraficAnalysis.last_period_df = last_period
|
| 854 |
|
| 855 |
#######################################################################################################"""
|
|
|
|
| 850 |
st.subheader("Multi-RAT Availability by site (post-period)")
|
| 851 |
st.dataframe(multi_rat_df.round(2))
|
| 852 |
|
| 853 |
+
worst_2g = None
|
| 854 |
+
if (
|
| 855 |
+
"2g_avail_post" in multi_rat_df.columns
|
| 856 |
+
and "ok_2g_post" in multi_rat_df.columns
|
| 857 |
+
and "post_total_data_trafic" in multi_rat_df.columns
|
| 858 |
+
):
|
| 859 |
+
tmp = multi_rat_df[
|
| 860 |
+
(multi_rat_df["ok_2g_post"] == False)
|
| 861 |
+
& multi_rat_df["post_total_data_trafic"].notna()
|
| 862 |
+
].copy()
|
| 863 |
+
if not tmp.empty:
|
| 864 |
+
worst_2g = tmp.sort_values(
|
| 865 |
+
"post_total_data_trafic", ascending=False
|
| 866 |
+
).head(number_of_top_trafic_sites)
|
| 867 |
+
|
| 868 |
+
worst_3g = None
|
| 869 |
+
if (
|
| 870 |
+
"3g_avail_post" in multi_rat_df.columns
|
| 871 |
+
and "ok_3g_post" in multi_rat_df.columns
|
| 872 |
+
and "post_total_data_trafic" in multi_rat_df.columns
|
| 873 |
+
):
|
| 874 |
+
tmp = multi_rat_df[
|
| 875 |
+
(multi_rat_df["ok_3g_post"] == False)
|
| 876 |
+
& multi_rat_df["post_total_data_trafic"].notna()
|
| 877 |
+
].copy()
|
| 878 |
+
if not tmp.empty:
|
| 879 |
+
worst_3g = tmp.sort_values(
|
| 880 |
+
"post_total_data_trafic", ascending=False
|
| 881 |
+
).head(number_of_top_trafic_sites)
|
| 882 |
+
|
| 883 |
+
worst_lte = None
|
| 884 |
+
if (
|
| 885 |
+
"lte_avail_post" in multi_rat_df.columns
|
| 886 |
+
and "ok_lte_post" in multi_rat_df.columns
|
| 887 |
+
and "post_total_data_trafic" in multi_rat_df.columns
|
| 888 |
+
):
|
| 889 |
+
tmp = multi_rat_df[
|
| 890 |
+
(multi_rat_df["ok_lte_post"] == False)
|
| 891 |
+
& multi_rat_df["post_total_data_trafic"].notna()
|
| 892 |
+
].copy()
|
| 893 |
+
if not tmp.empty:
|
| 894 |
+
worst_lte = tmp.sort_values(
|
| 895 |
+
"post_total_data_trafic", ascending=False
|
| 896 |
+
).head(number_of_top_trafic_sites)
|
| 897 |
+
|
| 898 |
+
st.subheader(
|
| 899 |
+
f"Worst high-traffic & low-availability sites by RAT (top {number_of_top_trafic_sites}, post-period)"
|
| 900 |
+
)
|
| 901 |
+
tab_2g, tab_3g, tab_lte = st.tabs(["2G", "3G", "LTE"])
|
| 902 |
+
|
| 903 |
+
with tab_2g:
|
| 904 |
+
if worst_2g is not None and not worst_2g.empty:
|
| 905 |
+
st.dataframe(worst_2g.round(2))
|
| 906 |
+
else:
|
| 907 |
+
st.info(
|
| 908 |
+
"No 2G sites with low availability and significant traffic in post-period."
|
| 909 |
+
)
|
| 910 |
+
|
| 911 |
+
with tab_3g:
|
| 912 |
+
if worst_3g is not None and not worst_3g.empty:
|
| 913 |
+
st.dataframe(worst_3g.round(2))
|
| 914 |
+
else:
|
| 915 |
+
st.info(
|
| 916 |
+
"No 3G sites with low availability and significant traffic in post-period."
|
| 917 |
+
)
|
| 918 |
+
|
| 919 |
+
with tab_lte:
|
| 920 |
+
if worst_lte is not None and not worst_lte.empty:
|
| 921 |
+
st.dataframe(worst_lte.round(2))
|
| 922 |
+
else:
|
| 923 |
+
st.info(
|
| 924 |
+
"No LTE sites with low availability and significant traffic in post-period."
|
| 925 |
+
)
|
| 926 |
+
|
| 927 |
+
# Temporal availability analysis - daily averages per RAT
|
| 928 |
+
if any(
|
| 929 |
+
col in full_df.columns
|
| 930 |
+
for col in ["2g_tch_avail", "3g_cell_avail", "lte_cell_avail"]
|
| 931 |
+
):
|
| 932 |
+
temp_df = full_df.copy()
|
| 933 |
+
temp_df["date_only"] = temp_df["date"].dt.date
|
| 934 |
+
|
| 935 |
+
agg_dict = {}
|
| 936 |
+
if "2g_tch_avail" in temp_df.columns:
|
| 937 |
+
agg_dict["2g_tch_avail"] = "mean"
|
| 938 |
+
if "3g_cell_avail" in temp_df.columns:
|
| 939 |
+
agg_dict["3g_cell_avail"] = "mean"
|
| 940 |
+
if "lte_cell_avail" in temp_df.columns:
|
| 941 |
+
agg_dict["lte_cell_avail"] = "mean"
|
| 942 |
+
|
| 943 |
+
daily_avail = (
|
| 944 |
+
temp_df.groupby("date_only", as_index=False).agg(agg_dict)
|
| 945 |
+
if agg_dict
|
| 946 |
+
else pd.DataFrame()
|
| 947 |
+
)
|
| 948 |
+
|
| 949 |
+
if not daily_avail.empty:
|
| 950 |
+
rename_map = {}
|
| 951 |
+
if "2g_tch_avail" in daily_avail.columns:
|
| 952 |
+
rename_map["2g_tch_avail"] = "2G"
|
| 953 |
+
if "3g_cell_avail" in daily_avail.columns:
|
| 954 |
+
rename_map["3g_cell_avail"] = "3G"
|
| 955 |
+
if "lte_cell_avail" in daily_avail.columns:
|
| 956 |
+
rename_map["lte_cell_avail"] = "LTE"
|
| 957 |
+
|
| 958 |
+
daily_avail = daily_avail.rename(columns=rename_map)
|
| 959 |
+
|
| 960 |
+
value_cols = [c for c in daily_avail.columns if c != "date_only"]
|
| 961 |
+
if value_cols:
|
| 962 |
+
daily_melt = daily_avail.melt(
|
| 963 |
+
id_vars="date_only",
|
| 964 |
+
value_vars=value_cols,
|
| 965 |
+
var_name="RAT",
|
| 966 |
+
value_name="availability",
|
| 967 |
+
)
|
| 968 |
+
|
| 969 |
+
st.subheader("Daily average availability per RAT")
|
| 970 |
+
fig = px.line(
|
| 971 |
+
daily_melt,
|
| 972 |
+
x="date_only",
|
| 973 |
+
y="availability",
|
| 974 |
+
color="RAT",
|
| 975 |
+
markers=True,
|
| 976 |
+
)
|
| 977 |
+
st.plotly_chart(fig)
|
| 978 |
+
|
| 979 |
+
degraded_rows = []
|
| 980 |
+
for rat_name, sla_value in [
|
| 981 |
+
("2G", sla_2g),
|
| 982 |
+
("3G", sla_3g),
|
| 983 |
+
("LTE", sla_lte),
|
| 984 |
+
]:
|
| 985 |
+
if rat_name in daily_avail.columns:
|
| 986 |
+
series = daily_avail[rat_name]
|
| 987 |
+
mask = series < sla_value
|
| 988 |
+
for d, val in zip(
|
| 989 |
+
daily_avail.loc[mask, "date_only"], series[mask]
|
| 990 |
+
):
|
| 991 |
+
degraded_rows.append(
|
| 992 |
+
{
|
| 993 |
+
"RAT": rat_name,
|
| 994 |
+
"date": d,
|
| 995 |
+
"avg_availability": val,
|
| 996 |
+
"SLA": sla_value,
|
| 997 |
+
}
|
| 998 |
+
)
|
| 999 |
+
|
| 1000 |
+
if degraded_rows:
|
| 1001 |
+
degraded_df = pd.DataFrame(degraded_rows)
|
| 1002 |
+
st.subheader("Days with average availability below SLA")
|
| 1003 |
+
st.dataframe(degraded_df.round(2))
|
| 1004 |
+
|
| 1005 |
TraficAnalysis.last_period_df = last_period
|
| 1006 |
|
| 1007 |
#######################################################################################################"""
|