AR1769's picture
Create app.py
46695b5 verified
import pandas as pd
import gradio as gr
from sklearn.preprocessing import StandardScaler
from sklearn.svm import OneClassSVM
# Function to detect theft and provide insights
def detect_theft_from_file(uploaded_file):
# Determine the file type and read it
if uploaded_file.name.endswith('.csv'):
df = pd.read_csv(uploaded_file.name)
elif uploaded_file.name.endswith(('.xlsx', '.xls')):
df = pd.read_excel(uploaded_file.name)
else:
return "Unsupported file format. Please upload a CSV or Excel file."
# Ensure required format (Consumer ID + 12 months + optional Last Year)
if len(df.columns) < 13:
return "The file must have at least 13 columns: 'Consumer ID', 12 months (e.g., Jan-Dec), and optionally 'Last Year Avg'."
feature_columns = df.columns[1:13] # 12 months
data = df[feature_columns].values
# Normalize the data
scaler = StandardScaler()
data_scaled = scaler.fit_transform(data)
# One-Class SVM model
model = OneClassSVM(nu=0.1, kernel='rbf', gamma='scale')
model.fit(data_scaled)
# Predict anomalies
predictions = model.predict(data_scaled)
# Add Reasons and Tips
reasons = []
tips = []
for i, pred in enumerate(predictions):
if pred == -1: # Theft detected
current_pattern = data[i]
if 'Last Year Avg' in df.columns:
last_year_avg = df['Last Year Avg'].iloc[i]
if current_pattern.mean() < 0.5 * last_year_avg:
reasons.append("Unusual drop compared to last year's average.")
elif current_pattern.mean() > 1.5 * last_year_avg:
reasons.append("Unusual rise compared to last year's average.")
else:
reasons.append("Irregular monthly pattern detected.")
else:
reasons.append("Irregular monthly pattern detected.")
tips.append(
"1. Inspect the meter physically for tampering.\n"
"2. Compare with neighborhood usage for similar consumption patterns.\n"
"3. Check if there are bypass connections or rewiring."
)
else: # No theft detected
reasons.append("No irregularities detected.")
tips.append("No action required.")
# Results
df['Anomaly'] = ['Theft' if pred == -1 else 'No Theft' for pred in predictions]
df['Reason'] = reasons
df['Tips'] = tips
return df[['Consumer ID', 'Anomaly', 'Reason', 'Tips']]
# Function for manual input detection
def detect_theft_from_manual_input(consumer_id, *monthly_kwh):
# Create a DataFrame from manual input
df = pd.DataFrame(
{
'Consumer ID': [consumer_id],
**{f'Month {i+1}': [monthly_kwh[i]] for i in range(12)},
}
)
# Normalize the data
data = df.iloc[:, 1:].values # Select monthly data
scaler = StandardScaler()
data_scaled = scaler.fit_transform(data)
# One-Class SVM model
model = OneClassSVM(nu=0.1, kernel='rbf', gamma='scale')
model.fit(data_scaled)
# Predict anomaly
prediction = model.predict(data_scaled)
# Add Reason and Tips
if prediction[0] == -1: # Theft detected
reason = "Irregular monthly pattern detected."
tips = (
"1. Inspect the meter physically for tampering.\n"
"2. Compare with neighborhood usage for similar consumption patterns.\n"
"3. Check if there are bypass connections or rewiring."
)
else:
reason = "No irregularities detected."
tips = "No action required."
df['Anomaly'] = ['Theft' if prediction[0] == -1 else 'No Theft']
df['Reason'] = [reason]
df['Tips'] = [tips]
return df[['Consumer ID', 'Anomaly', 'Reason', 'Tips']]
# Gradio Interface
file_interface = gr.Interface(
fn=detect_theft_from_file,
inputs=gr.File(label="Upload Meter Data File (CSV, XLSX, XLS)"),
outputs=gr.Dataframe(label="Meter Theft Detection")
)
manual_input_interface = gr.Interface(
fn=detect_theft_from_manual_input,
inputs=[
gr.Textbox(label="Consumer ID", placeholder="Enter Consumer ID"),
*[gr.Number(label=f"Month {i+1} kWh") for i in range(12)],
],
outputs=gr.Dataframe(label="Meter Theft Detection")
)
# Combine interfaces
iface = gr.TabbedInterface(
interface_list=[file_interface, manual_input_interface],
tab_names=["Upload File", "Manual Input"]
)
# Launch the Gradio app
iface.launch()