DavMelchi commited on
Commit
c98bb3f
·
1 Parent(s): 337f0be

gsm capacity part2 with comments analysis and combinations

Browse files
README.md CHANGED
@@ -49,7 +49,7 @@ You can access the hosted version of the app at [https://davmelchi-db-query.hf.s
49
  - [x] Symetric neighbours checking
50
  - [x] Add the ability to select columns
51
  - [x] Add authentication
 
52
  - [ ] Improve Dashboard
53
  - [ ] Error handling
54
- - [ ] frequency distribution GSM
55
  - [ ] Add KPI analysis App
 
49
  - [x] Symetric neighbours checking
50
  - [x] Add the ability to select columns
51
  - [x] Add authentication
52
+ - [x] Initial frequency distribution chart GSM
53
  - [ ] Improve Dashboard
54
  - [ ] Error handling
 
55
  - [ ] Add KPI analysis App
apps/kpi_analysis/gsm_capacity.py CHANGED
@@ -42,6 +42,8 @@ col1, col2 = st.columns(2)
42
 
43
  threshold_col1, threshold_col2 = st.columns(2)
44
  threshold_col3, threshold_col4 = st.columns(2)
 
 
45
 
46
  if (
47
  uploaded_dump is not None
@@ -80,6 +82,14 @@ if (
80
  tch_blocking_threshold = st.number_input(
81
  "TCH Blocking Threshold", min_value=0.1, value=0.5
82
  )
 
 
 
 
 
 
 
 
83
 
84
  if st.button("Analyze Data", type="primary"):
85
  dfs = analyze_gsm_data(
@@ -92,12 +102,13 @@ if (
92
  tch_abis_fails_threshold=tch_abis_fails_threshold,
93
  sdcch_blocking_threshold=sdcch_blocking_threshold,
94
  tch_blocking_threshold=tch_blocking_threshold,
 
95
  )
96
 
97
  if dfs is not None:
98
- gsm_analysis_df = dfs[0]
99
- bh_kpi_df = dfs[1]
100
- daily_kpi_df = dfs[2]
101
  GsmCapacity.final_results = convert_gsm_dfs(
102
  [gsm_analysis_df, bh_kpi_df, daily_kpi_df],
103
  ["GSM_Analysis", "BH_KPI_Analysis", "Daily_KPI_Analysis"],
@@ -118,3 +129,36 @@ if (
118
  )
119
 
120
  st.write(daily_kpi_df)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
  threshold_col1, threshold_col2 = st.columns(2)
44
  threshold_col3, threshold_col4 = st.columns(2)
45
+ max_traffic_threshold_col1, max_traffic_threshold_col2 = st.columns(2)
46
+
47
 
48
  if (
49
  uploaded_dump is not None
 
82
  tch_blocking_threshold = st.number_input(
83
  "TCH Blocking Threshold", min_value=0.1, value=0.5
84
  )
85
+ with max_traffic_threshold_col1:
86
+ max_traffic_threshold = st.number_input(
87
+ "TCH Utilization Max Traffic Threshold", min_value=0, value=90
88
+ )
89
+ # with max_traffic_threshold_col2:
90
+ # max_traffic_threshold = st.number_input(
91
+ # "Max Traffic Threshold", min_value=0, value=10
92
+ # )
93
 
94
  if st.button("Analyze Data", type="primary"):
95
  dfs = analyze_gsm_data(
 
102
  tch_abis_fails_threshold=tch_abis_fails_threshold,
103
  sdcch_blocking_threshold=sdcch_blocking_threshold,
104
  tch_blocking_threshold=tch_blocking_threshold,
105
+ max_traffic_threshold=max_traffic_threshold,
106
  )
107
 
108
  if dfs is not None:
109
+ gsm_analysis_df: pd.DataFrame = dfs[0]
110
+ bh_kpi_df: pd.DataFrame = dfs[1]
111
+ daily_kpi_df: pd.DataFrame = dfs[2]
112
  GsmCapacity.final_results = convert_gsm_dfs(
113
  [gsm_analysis_df, bh_kpi_df, daily_kpi_df],
114
  ["GSM_Analysis", "BH_KPI_Analysis", "Daily_KPI_Analysis"],
 
129
  )
130
 
131
  st.write(daily_kpi_df)
132
+
133
+ # Add dataframe and ploty bar chart with "Final comment" distribution in gsm_analysis_df in 2 columns
134
+ final_comments_df = (
135
+ gsm_analysis_df.groupby("Final comment").size().reset_index(name="count")
136
+ )
137
+ fig = px.bar(final_comments_df, x="Final comment", y="count")
138
+ fig.update_layout(height=1500)
139
+ fig.update_traces(texttemplate="%{value}", textposition="outside")
140
+ st.plotly_chart(fig, use_container_width=True)
141
+ st.write(final_comments_df)
142
+
143
+ # Add dataframe and ploty bar chart with "BH Congestion status" distribution in gsm_analysis_df in 2 columns
144
+ bh_congestion_status_df = (
145
+ gsm_analysis_df.groupby("BH Congestion status")
146
+ .size()
147
+ .reset_index(name="count")
148
+ )
149
+ fig = px.bar(bh_congestion_status_df, x="BH Congestion status", y="count")
150
+ fig.update_layout(height=1500)
151
+ fig.update_traces(texttemplate="%{value}", textposition="outside")
152
+ st.plotly_chart(fig, use_container_width=True)
153
+ st.write(bh_congestion_status_df)
154
+ # Add dataframe and ploty bar chart with "operational_comment" distribution in gsm_analysis_df in 2 columns
155
+ operational_comments_df = (
156
+ gsm_analysis_df.groupby("operational_comment")
157
+ .size()
158
+ .reset_index(name="count")
159
+ )
160
+ fig = px.bar(operational_comments_df, x="operational_comment", y="count")
161
+ fig.update_layout(height=1500)
162
+ fig.update_traces(texttemplate="%{value}", textposition="outside")
163
+ st.plotly_chart(fig, use_container_width=True)
164
+ st.write(operational_comments_df)
process_kpi/process_gsm_capacity.py CHANGED
@@ -6,6 +6,9 @@ from utils.check_sheet_exist import execute_checks_sheets_exist
6
  from utils.convert_to_excel import convert_dfs, save_dataframe
7
  from utils.kpi_analysis_utils import (
8
  GsmAnalysis,
 
 
 
9
  cell_availability_analysis,
10
  combine_comments,
11
  create_daily_date,
@@ -74,114 +77,19 @@ BH_COLUMNS_FOR_CAPACITY = [
74
  "max_sdcch_real_blocking_bh",
75
  "avg_sdcch_real_blocking_bh",
76
  "number_of_days_with_sdcch_blocking_exceeded_bh",
 
 
77
  ]
78
 
79
-
80
- def analyze_tch_abis_fails(
81
- df: pd.DataFrame,
82
- number_of_kpi_days: int,
83
- analysis_type: str,
84
- number_of_threshold_days: int,
85
- tch_abis_fails_threshold: int,
86
- ) -> pd.DataFrame:
87
-
88
- result_df = df.copy()
89
- last_days_df = result_df.iloc[:, -number_of_kpi_days:]
90
- # last_days_df = last_days_df.fillna(0)
91
-
92
- result_df[f"avg_tch_abis_fail_{analysis_type.lower()}"] = last_days_df.mean(
93
- axis=1
94
- ).round(2)
95
- result_df[f"max_tch_abis_fail_{analysis_type.lower()}"] = last_days_df.max(axis=1)
96
- # Count the number of days above threshold
97
- result_df[f"number_of_days_with_tch_abis_fail_exceeded_{analysis_type.lower()}"] = (
98
- last_days_df.apply(
99
- lambda row: sum(1 for x in row if x >= tch_abis_fails_threshold), axis=1
100
- )
101
- )
102
-
103
- # Add the daily_tch_comment : if number_of_days_with_tch_abis_fail_exceeded_daily is >= number_of_threshold_days : tch abis fail exceeded treshold , else : None
104
- result_df[f"tch_abis_fail_{analysis_type.lower()}_comment"] = np.where(
105
- result_df[f"number_of_days_with_tch_abis_fail_exceeded_{analysis_type.lower()}"]
106
- >= number_of_threshold_days,
107
- "tch abis fail exceeded treshold",
108
- None,
109
- )
110
-
111
- return result_df
112
-
113
-
114
- def analyze_tch_call_blocking(
115
- df: pd.DataFrame,
116
- number_of_kpi_days: int,
117
- analysis_type: str,
118
- number_of_threshold_days: int,
119
- tch_blocking_threshold: int,
120
- ) -> pd.DataFrame:
121
-
122
- result_df = df.copy()
123
- last_days_df = result_df.iloc[:, -number_of_kpi_days:]
124
- # last_days_df = last_days_df.fillna(0)
125
-
126
- result_df[f"avg_tch_call_blocking_{analysis_type.lower()}"] = last_days_df.mean(
127
- axis=1
128
- ).round(2)
129
- result_df[f"max_tch_call_blocking_{analysis_type.lower()}"] = last_days_df.max(
130
- axis=1
131
- )
132
- # Count the number of days above threshold
133
- result_df[f"number_of_days_with_tch_blocking_exceeded_{analysis_type.lower()}"] = (
134
- last_days_df.apply(
135
- lambda row: sum(1 for x in row if x >= tch_blocking_threshold), axis=1
136
- )
137
- )
138
-
139
- # Add the daily_tch_comment : if number_of_days_with_tch_blocking_exceeded_daily is >= number_of_threshold_days : tch blocking exceeded treshold , else : None
140
- result_df[f"tch_call_blocking_{analysis_type.lower()}_comment"] = np.where(
141
- result_df[f"number_of_days_with_tch_blocking_exceeded_{analysis_type.lower()}"]
142
- >= number_of_threshold_days,
143
- "TCH blocking exceeded threshold",
144
- None,
145
- )
146
- return result_df
147
-
148
-
149
- def analyze_sdcch_call_blocking(
150
- df: pd.DataFrame,
151
- number_of_kpi_days: int,
152
- sdcch_blocking_threshold: int,
153
- analysis_type: str,
154
- number_of_threshold_days: int,
155
- ) -> pd.DataFrame:
156
-
157
- result_df = df.copy()
158
- last_days_df = result_df.iloc[:, -number_of_kpi_days:]
159
- # last_days_df = last_days_df.fillna(0)
160
-
161
- result_df[f"avg_sdcch_real_blocking_{analysis_type.lower()}"] = last_days_df.mean(
162
- axis=1
163
- ).round(2)
164
- result_df[f"max_sdcch_real_blocking_{analysis_type.lower()}"] = last_days_df.max(
165
- axis=1
166
- )
167
- # Count the number of days above threshold
168
- result_df[
169
- f"number_of_days_with_sdcch_blocking_exceeded_{analysis_type.lower()}"
170
- ] = last_days_df.apply(
171
- lambda row: sum(1 for x in row if x >= sdcch_blocking_threshold), axis=1
172
- )
173
-
174
- # add daily_sdcch_comment : if number_of_days_with_sdcch_blocking_exceeded_daily is >= number_of_threshold_days : sdcch blocking exceeded treshold , else : None
175
- result_df[f"sdcch_real_blocking_{analysis_type.lower()}_comment"] = np.where(
176
- result_df[
177
- f"number_of_days_with_sdcch_blocking_exceeded_{analysis_type.lower()}"
178
- ]
179
- >= number_of_threshold_days,
180
- "SDCCH blocking exceeded threshold",
181
- None,
182
- )
183
-
184
- return result_df
185
 
186
 
187
  def bh_traffic_analysis(
@@ -190,7 +98,7 @@ def bh_traffic_analysis(
190
  ) -> pd.DataFrame:
191
 
192
  result_df = df.copy()
193
- last_days_df = result_df.iloc[:, -number_of_kpi_days:]
194
  # last_days_df = last_days_df.fillna(0)
195
 
196
  result_df["Avg_Traffic BH"] = last_days_df.mean(axis=1).round(2)
@@ -282,6 +190,7 @@ def analyse_bh_data(
282
  number_of_kpi_days=number_of_kpi_days,
283
  tch_blocking_threshold=tch_blocking_threshold,
284
  sdcch_blocking_threshold=sdcch_blocking_threshold,
 
285
  )
286
 
287
  bh_df_for_capacity = df.copy()
@@ -416,7 +325,19 @@ def analyse_daily_data(
416
  sdcch_blocking_threshold=sdcch_blocking_threshold,
417
  tch_blocking_threshold=tch_blocking_threshold,
418
  )
419
- return df
 
 
 
 
 
 
 
 
 
 
 
 
420
 
421
 
422
  def get_gsm_databases(dump_path: str) -> pd.DataFrame:
@@ -468,9 +389,10 @@ def analyze_gsm_data(
468
  tch_abis_fails_threshold: int,
469
  sdcch_blocking_threshold: float,
470
  tch_blocking_threshold: float,
 
471
  ):
472
 
473
- daily_kpi_df: pd.DataFrame = analyse_daily_data(
474
  daily_report_path=daily_report_path,
475
  number_of_kpi_days=number_of_kpi_days,
476
  availability_threshold=availability_threshold,
@@ -493,13 +415,32 @@ def analyze_gsm_data(
493
  bh_kpi_df = bh_kpi_dfs[0]
494
  bh_kpi_full_df = bh_kpi_dfs[1]
495
 
 
 
 
496
  gsm_analysis_df = gsm_database_df.merge(bh_kpi_df, on="name", how="left")
 
497
 
498
  # "TCH UTILIZATION (@Max Traffic)" equal to "(Max_Trafic" divided by "Offered Traffic BH)*100"
499
  gsm_analysis_df["TCH UTILIZATION (@Max Traffic)"] = (
500
  gsm_analysis_df["Max_Traffic BH"] / gsm_analysis_df["Offered Traffic BH"]
501
  ) * 100
502
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
503
  # Add "ERLANGB value" =MAX TRAFFIC/(1-(MAX TCH call blocking/200))
504
  gsm_analysis_df["ErlabngB_value"] = gsm_analysis_df["Max_Traffic BH"] / (
505
  1 - (gsm_analysis_df["max_tch_call_blocking_bh"] / 200)
@@ -530,4 +471,47 @@ def analyze_gsm_data(
530
  gsm_analysis_df["Target TRXs"] - gsm_analysis_df["number_trx_per_cell"]
531
  )
532
 
533
- return [gsm_analysis_df, bh_kpi_full_df, daily_kpi_df]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  from utils.convert_to_excel import convert_dfs, save_dataframe
7
  from utils.kpi_analysis_utils import (
8
  GsmAnalysis,
9
+ analyze_sdcch_call_blocking,
10
+ analyze_tch_abis_fails,
11
+ analyze_tch_call_blocking,
12
  cell_availability_analysis,
13
  combine_comments,
14
  create_daily_date,
 
77
  "max_sdcch_real_blocking_bh",
78
  "avg_sdcch_real_blocking_bh",
79
  "number_of_days_with_sdcch_blocking_exceeded_bh",
80
+ "tch_call_blocking_bh_comment",
81
+ "sdcch_real_blocking_bh_comment",
82
  ]
83
 
84
+ DAILY_COLUMNS_FOR_CAPACITY = [
85
+ "Average_cell_availability",
86
+ "number_of_days_exceeding_threshold",
87
+ "availability_comment",
88
+ "avg_tch_abis_fail_daily",
89
+ "max_tch_abis_fail_daily",
90
+ "number_of_days_with_tch_abis_fail_exceeded_daily",
91
+ "tch_abis_fail_daily_comment",
92
+ ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
 
94
 
95
  def bh_traffic_analysis(
 
98
  ) -> pd.DataFrame:
99
 
100
  result_df = df.copy()
101
+ last_days_df: pd.DataFrame = result_df.iloc[:, -number_of_kpi_days:]
102
  # last_days_df = last_days_df.fillna(0)
103
 
104
  result_df["Avg_Traffic BH"] = last_days_df.mean(axis=1).round(2)
 
190
  number_of_kpi_days=number_of_kpi_days,
191
  tch_blocking_threshold=tch_blocking_threshold,
192
  sdcch_blocking_threshold=sdcch_blocking_threshold,
193
+ number_of_threshold_days=number_of_threshold_days,
194
  )
195
 
196
  bh_df_for_capacity = df.copy()
 
325
  sdcch_blocking_threshold=sdcch_blocking_threshold,
326
  tch_blocking_threshold=tch_blocking_threshold,
327
  )
328
+ daily_df_for_capacity = df.copy()
329
+ daily_df_for_capacity = daily_df_for_capacity[DAILY_COLUMNS_FOR_CAPACITY]
330
+ daily_df_for_capacity = daily_df_for_capacity.reset_index()
331
+
332
+ if isinstance(daily_df_for_capacity.columns, pd.MultiIndex):
333
+ daily_df_for_capacity.columns = [
334
+ "_".join([str(el) for el in col if el])
335
+ for col in daily_df_for_capacity.columns.values
336
+ ]
337
+ # Rename "BTS_name" to "name"
338
+ daily_df_for_capacity = daily_df_for_capacity.rename(columns={"BTS_name": "name"})
339
+
340
+ return daily_df_for_capacity, df
341
 
342
 
343
  def get_gsm_databases(dump_path: str) -> pd.DataFrame:
 
389
  tch_abis_fails_threshold: int,
390
  sdcch_blocking_threshold: float,
391
  tch_blocking_threshold: float,
392
+ max_traffic_threshold: int,
393
  ):
394
 
395
+ daily_kpi_dfs: pd.DataFrame = analyse_daily_data(
396
  daily_report_path=daily_report_path,
397
  number_of_kpi_days=number_of_kpi_days,
398
  availability_threshold=availability_threshold,
 
415
  bh_kpi_df = bh_kpi_dfs[0]
416
  bh_kpi_full_df = bh_kpi_dfs[1]
417
 
418
+ daily_kpi_df = daily_kpi_dfs[0]
419
+ daily_kpi_full_df = daily_kpi_dfs[1]
420
+
421
  gsm_analysis_df = gsm_database_df.merge(bh_kpi_df, on="name", how="left")
422
+ gsm_analysis_df = gsm_analysis_df.merge(daily_kpi_df, on="name", how="left")
423
 
424
  # "TCH UTILIZATION (@Max Traffic)" equal to "(Max_Trafic" divided by "Offered Traffic BH)*100"
425
  gsm_analysis_df["TCH UTILIZATION (@Max Traffic)"] = (
426
  gsm_analysis_df["Max_Traffic BH"] / gsm_analysis_df["Offered Traffic BH"]
427
  ) * 100
428
 
429
+ # Add column "Tch utilization comments" : if "TCH UTILIZATION (@Max Traffic)" exceeded it's threshold then "Tch utilization exceeded threshold else None
430
+ gsm_analysis_df["Tch utilization comments"] = np.where(
431
+ gsm_analysis_df["TCH UTILIZATION (@Max Traffic)"] > max_traffic_threshold,
432
+ "Tch utilization exceeded threshold",
433
+ None,
434
+ )
435
+ # Add "BH Congestion status" : concatenate "Tch utilization comments" + "tch_call_blocking_bh_comment" + "sdcch_real_blocking_bh_comment"
436
+ gsm_analysis_df = combine_comments(
437
+ gsm_analysis_df,
438
+ "Tch utilization comments",
439
+ "tch_call_blocking_bh_comment",
440
+ "sdcch_real_blocking_bh_comment",
441
+ new_column="BH Congestion status",
442
+ )
443
+
444
  # Add "ERLANGB value" =MAX TRAFFIC/(1-(MAX TCH call blocking/200))
445
  gsm_analysis_df["ErlabngB_value"] = gsm_analysis_df["Max_Traffic BH"] / (
446
  1 - (gsm_analysis_df["max_tch_call_blocking_bh"] / 200)
 
471
  gsm_analysis_df["Target TRXs"] - gsm_analysis_df["number_trx_per_cell"]
472
  )
473
 
474
+ # if "availability_comment" equal to "Down Site" then "Down Site"
475
+ # if "availability_comment" is not "Availability OK" and "tch_abis_fail_daily_comment" equal to "tch abis fail exceeded threshold" then "Availability and TX issues"
476
+ # if "availability_comment" is not "Availability OK" and "tch_abis_fail_daily_comment" is empty then "Availability issues"
477
+ # if "availability_comment" is "Availability OK" and "tch_abis_fail_daily_comment" equal to "tch abis fail exceeded threshold" then "TX issues"
478
+ # Else "Operational is OK"
479
+ gsm_analysis_df["operational_comment"] = np.select(
480
+ [
481
+ gsm_analysis_df["availability_comment"] == "Down Site", # 1
482
+ (gsm_analysis_df["availability_comment"] != "Availability OK")
483
+ & (
484
+ gsm_analysis_df["tch_abis_fail_daily_comment"]
485
+ == "tch abis fail exceeded threshold"
486
+ ), # 2
487
+ (gsm_analysis_df["availability_comment"] != "Availability OK")
488
+ & pd.isna(gsm_analysis_df["tch_abis_fail_daily_comment"]), # 3
489
+ (gsm_analysis_df["availability_comment"] == "Availability OK")
490
+ & (
491
+ gsm_analysis_df["tch_abis_fail_daily_comment"]
492
+ == "tch abis fail exceeded threshold"
493
+ ), # 4
494
+ ],
495
+ [
496
+ "Down Site", # 1
497
+ "Availability and TX issues", # 2
498
+ "Availability issues", # 3
499
+ "TX issues", # 4
500
+ ],
501
+ default="Operational is OK",
502
+ )
503
+
504
+ # Add "Final comment" with "BH Congestion status" + "operational_comment"
505
+ gsm_analysis_df = combine_comments(
506
+ gsm_analysis_df,
507
+ "BH Congestion status",
508
+ "operational_comment",
509
+ new_column="Final comment",
510
+ )
511
+
512
+ # Replace 'nan, nan, Availability issues' with None
513
+ # gsm_analysis_df["Final comment"] = gsm_analysis_df["Final comment"].replace(
514
+ # "nan, nan, Availability issues", None
515
+ # )
516
+
517
+ return [gsm_analysis_df, bh_kpi_full_df, daily_kpi_full_df]
utils/kpi_analysis_utils.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import pandas as pd
2
 
3
 
@@ -230,7 +231,7 @@ def combine_comments(df: pd.DataFrame, *columns: str, new_column: str) -> pd.Dat
230
  """
231
  result_df = df.copy()
232
  result_df[new_column] = result_df[list(columns)].apply(
233
- lambda row: ", ".join([x for x in row if x]), axis=1
234
  )
235
  # Trim all trailing commas
236
  result_df[new_column] = result_df[new_column].str.replace(
@@ -384,3 +385,110 @@ def cell_availability_analysis(
384
  )
385
 
386
  return result_df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
  import pandas as pd
3
 
4
 
 
231
  """
232
  result_df = df.copy()
233
  result_df[new_column] = result_df[list(columns)].apply(
234
+ lambda row: ", ".join([str(x) for x in row if x]), axis=1
235
  )
236
  # Trim all trailing commas
237
  result_df[new_column] = result_df[new_column].str.replace(
 
385
  )
386
 
387
  return result_df
388
+
389
+
390
+ def analyze_tch_abis_fails(
391
+ df: pd.DataFrame,
392
+ number_of_kpi_days: int,
393
+ analysis_type: str,
394
+ number_of_threshold_days: int,
395
+ tch_abis_fails_threshold: int,
396
+ ) -> pd.DataFrame:
397
+
398
+ result_df = df.copy()
399
+ last_days_df: pd.DataFrame = result_df.iloc[:, -number_of_kpi_days:]
400
+ # last_days_df = last_days_df.fillna(0)
401
+
402
+ result_df[f"avg_tch_abis_fail_{analysis_type.lower()}"] = last_days_df.mean(
403
+ axis=1
404
+ ).round(2)
405
+ result_df[f"max_tch_abis_fail_{analysis_type.lower()}"] = last_days_df.max(axis=1)
406
+ # Count the number of days above threshold
407
+ result_df[f"number_of_days_with_tch_abis_fail_exceeded_{analysis_type.lower()}"] = (
408
+ last_days_df.apply(
409
+ lambda row: sum(1 for x in row if x >= tch_abis_fails_threshold), axis=1
410
+ )
411
+ )
412
+
413
+ # Add the daily_tch_comment : if number_of_days_with_tch_abis_fail_exceeded_daily is >= number_of_threshold_days : tch abis fail exceeded threshold , else : None
414
+ result_df[f"tch_abis_fail_{analysis_type.lower()}_comment"] = np.where(
415
+ result_df[f"number_of_days_with_tch_abis_fail_exceeded_{analysis_type.lower()}"]
416
+ >= number_of_threshold_days,
417
+ "tch abis fail exceeded threshold",
418
+ None,
419
+ )
420
+
421
+ return result_df
422
+
423
+
424
+ def analyze_tch_call_blocking(
425
+ df: pd.DataFrame,
426
+ number_of_kpi_days: int,
427
+ analysis_type: str,
428
+ number_of_threshold_days: int,
429
+ tch_blocking_threshold: int,
430
+ ) -> pd.DataFrame:
431
+
432
+ result_df = df.copy()
433
+ last_days_df: pd.DataFrame = result_df.iloc[:, -number_of_kpi_days:]
434
+ # last_days_df = last_days_df.fillna(0)
435
+
436
+ result_df[f"avg_tch_call_blocking_{analysis_type.lower()}"] = last_days_df.mean(
437
+ axis=1
438
+ ).round(2)
439
+ result_df[f"max_tch_call_blocking_{analysis_type.lower()}"] = last_days_df.max(
440
+ axis=1
441
+ )
442
+ # Count the number of days above threshold
443
+ result_df[f"number_of_days_with_tch_blocking_exceeded_{analysis_type.lower()}"] = (
444
+ last_days_df.apply(
445
+ lambda row: sum(1 for x in row if x >= tch_blocking_threshold), axis=1
446
+ )
447
+ )
448
+
449
+ # Add the daily_tch_comment : if number_of_days_with_tch_blocking_exceeded_daily is >= number_of_threshold_days : tch blocking exceeded threshold , else : None
450
+ result_df[f"tch_call_blocking_{analysis_type.lower()}_comment"] = np.where(
451
+ result_df[f"number_of_days_with_tch_blocking_exceeded_{analysis_type.lower()}"]
452
+ >= number_of_threshold_days,
453
+ "TCH blocking exceeded threshold",
454
+ None,
455
+ )
456
+ return result_df
457
+
458
+
459
+ def analyze_sdcch_call_blocking(
460
+ df: pd.DataFrame,
461
+ number_of_kpi_days: int,
462
+ sdcch_blocking_threshold: int,
463
+ analysis_type: str,
464
+ number_of_threshold_days: int,
465
+ ) -> pd.DataFrame:
466
+
467
+ result_df = df.copy()
468
+ last_days_df: pd.DataFrame = result_df.iloc[:, -number_of_kpi_days:]
469
+ # last_days_df = last_days_df.fillna(0)
470
+
471
+ result_df[f"avg_sdcch_real_blocking_{analysis_type.lower()}"] = last_days_df.mean(
472
+ axis=1
473
+ ).round(2)
474
+ result_df[f"max_sdcch_real_blocking_{analysis_type.lower()}"] = last_days_df.max(
475
+ axis=1
476
+ )
477
+ # Count the number of days above threshold
478
+ result_df[
479
+ f"number_of_days_with_sdcch_blocking_exceeded_{analysis_type.lower()}"
480
+ ] = last_days_df.apply(
481
+ lambda row: sum(1 for x in row if x >= sdcch_blocking_threshold), axis=1
482
+ )
483
+
484
+ # add daily_sdcch_comment : if number_of_days_with_sdcch_blocking_exceeded_daily is >= number_of_threshold_days : sdcch blocking exceeded threshold , else : None
485
+ result_df[f"sdcch_real_blocking_{analysis_type.lower()}_comment"] = np.where(
486
+ result_df[
487
+ f"number_of_days_with_sdcch_blocking_exceeded_{analysis_type.lower()}"
488
+ ]
489
+ >= number_of_threshold_days,
490
+ "SDCCH blocking exceeded threshold",
491
+ None,
492
+ )
493
+
494
+ return result_df