#!/usr/bin/env python
# coding: utf-8

# # Welcome to Telco Churn Customers analysis and Prediction
# _______________________________________
# ![](http://dataskunkworks.com/wp-content/uploads/2018/05/churn-1024x482.png)
#

# ## Description of dataset
# ## Context
# "Predict behavior to retain customers. You can analyze all relevant customer data and develop focused customer retention programs." [IBM Sample Data Sets]
#
# ## Content
# Each row represents a customer, each column contains customer’s attributes described on the column Metadata.
#
# ## The data set includes information about:
#
# Customers who left within the last month – the column is called Churn

# Services that each customer has signed up for – phone, multiple lines, internet, online security, online backup, device protection, tech support, and streaming TV and movies

# Customer account information – how long they’ve been a customer, contract, payment method, paperless billing, monthly charges, and total charges

# Demographic info about customers – gender, age range, and if they have partners and dependents

# ## Inspiration
# To explore this type of models and learn more about the subject.
# __________________________________

# ## Objectives:
# I will explore the data and try to answer some questions like:
# - What's the % of Churn Customers and customers that keep in with the active services.
# - We can see different patterns in Churn Customers based on the type of service provided?
# - We have difference pattern of churn between genders ?
# - What's the difference between customers that pay monthly and by year?
# - what's the most profitable service types?
# - What's the amount lose in revenue?
# - What's the mean age of papeless customers? they are more propense to churn?
# - A lot of other questions that will raise trought the exploration
#
# ## After EDA
# I will build a pipeline to find a model that better fits our data.
# With the best models I will predict the result and verify the scores of the models.
#

# I hope you enjoy the Kernel.

#
#

# ## Importing Libraries

# In[ ]:

import numpy as np # linear algebra
from scipy import stats # statistic library
import pandas as pd # To table manipulations
import seaborn as sns
import matplotlib.pyplot as plt

# Standard plotly imports
import plotly.plotly as py
import plotly.graph_objs as go
import plotly.tools as tls
from plotly.offline import iplot, init_notebook_mode
import cufflinks
import cufflinks as cf
import plotly.figure_factory as ff

# Using plotly + cufflinks in offline mode
init_notebook_mode(connected=True)
cufflinks.go_offline(connected=True)

import os

#Importing the auxiliar and preprocessing librarys
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.utils.multiclass import unique_labels
from sklearn.model_selection import train_test_split, KFold, cross_validate

#Models
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
from sklearn.svm import SVC
from sklearn.linear_model import RidgeClassifier, SGDClassifier, LogisticRegression
from sklearn.svm import SVC, LinearSVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from xgboost import XGBClassifier
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, ExtraTreesClassifier
from sklearn.ensemble import BaggingClassifier, VotingClassifier, RandomTreesEmbedding

# In[ ]:

def binary_ploting_distributions(df, cat_col):
    from plotly import tools

    fig = tools.make_subplots(rows=1, cols=2, print_grid=True, horizontal_spacing=0.15, subplot_titles=("Distribution of and % Churn", f'Mean Monthly Charges of {cat_col}') )

    tmp_churn = df[df['Churn'] == 1]
    tmp_no_churn = df[df['Churn'] == 0]
    tmp_attr = round(tmp_churn[cat_col].value_counts().sort_index() / df_train[cat_col].value_counts().sort_index(),2)*100

    trace1 = go.Bar( x=tmp_churn[cat_col].value_counts().sort_index().index, y=tmp_churn[cat_col].value_counts().sort_index().values, name='Yes_Churn',opacity = 0.8, marker=dict( color='seagreen',             line=dict(color='#000000',width=1)))

    trace2 = go.Bar( x=tmp_no_churn[cat_col].value_counts().sort_index().index, y=tmp_no_churn[cat_col].value_counts().sort_index().values, name='No_Churn', opacity = 0.8, marker=dict( color='indianred',             line=dict(color='#000000', width=1) ) )

    trace3 =  go.Scatter( x=tmp_attr.sort_index().index, y=tmp_attr.sort_index().values, yaxis = 'y2', name='% Churn', opacity = 0.6, marker=dict( color='black',             line=dict(color='#000000', width=2 ) ) )

    df_tmp = (df_train.groupby(['Churn', cat_col])['MonthlyCharges'].mean().reset_index())

    tmp_churn = df_tmp[df_tmp['Churn'] == 1]
    tmp_no_churn = df_tmp[df_tmp['Churn'] == 0]

    df_tmp = (df_train.groupby(['Churn', cat_col])['MonthlyCharges'].mean()).unstack('Churn').reset_index()
    df_tmp['diff_rate'] = round((df_tmp[1] / df_tmp[0]) - 1,2) * 100

    trace4 = go.Bar( x=tmp_churn[cat_col], y=tmp_churn['MonthlyCharges'], showlegend=False, name='Mean Charge Churn',opacity = 0.8, marker=dict( color='seagreen',             line=dict(color='#000000',width=1)))

    trace5 = go.Bar( x=tmp_no_churn[cat_col], y=tmp_no_churn['MonthlyCharges'],showlegend=False, name='Mean Charge NoChurn', opacity = 0.8, marker=dict( color='indianred',             line=dict(color='#000000', width=1) ) )

    trace6 =  go.Scatter( x=df_tmp[cat_col], y=df_tmp['diff_rate'], yaxis = 'y2', name='% Diff Churn', opacity = 0.6, marker=dict( color='black',             line=dict(color='#000000', width=5 ) ) )

    fig.append_trace(trace1, 1, 1)
    fig.append_trace(trace2, 1, 1)
    fig.append_trace(trace3, 1, 1)
    fig.append_trace(trace4, 1, 2)
    fig.append_trace(trace5, 1, 2)
    fig.append_trace(trace6, 1, 2)

    fig['data'][2].update(yaxis='y3')
    fig['data'][5].update(yaxis='y4')

    fig['layout']['xaxis'].update(autorange=True, tickfont=dict(size= 10), title= f'{cat_col}', type= 'category', )
    fig['layout']['yaxis'].update(title= 'Count')

    fig['layout']['xaxis2'].update(autorange=True, tickfont=dict(size= 10), title= f'{cat_col}', type= 'category', )
    fig['layout']['yaxis2'].update( title= 'Mean Monthly Charges' )

    fig['layout']['yaxis3']=dict(range= [0, 100],  overlaying= 'y', anchor= 'x', side= 'right', showgrid= False, title= '%Churn Ratio' )

    #Insert a new key, yaxis4, and the associated value:
    fig['layout']['yaxis4']=dict(range= [-20, 100],  overlaying= 'y2', anchor= 'x2', side= 'right', showgrid= False, title= 'Monhtly % Difference' )
    fig['layout']['title'] = f"{cat_col} Distributions"
    fig['layout']['height'] = 500
    fig['layout']['width'] = 1000

    iplot(fig)

def plot_dist_churn(df, col, binary=None):
    tmp_churn = df[df[binary] == 1]
    tmp_no_churn = df[df[binary] == 0]
    tmp_attr = round(tmp_churn[col].value_counts().sort_index() / df[col].value_counts().sort_index(),2)*100
    print(f'Distribution of {col}: ')
    trace1 = go.Bar( x=tmp_churn[col].value_counts().sort_index().index, y=tmp_churn[col].value_counts().sort_index().values, name='Yes_Churn',opacity = 0.8, marker=dict( color='seagreen',             line=dict(color='#000000',width=1)))

    trace2 = go.Bar( x=tmp_no_churn[col].value_counts().sort_index().index, y=tmp_no_churn[col].value_counts().sort_index().values, name='No_Churn', opacity = 0.8, marker=dict( color='indianred',             line=dict(color='#000000', width=1) ) )

    trace3 =  go.Scatter( x=tmp_attr.sort_index().index, y=tmp_attr.sort_index().values, yaxis = 'y2', name='% Churn', opacity = 0.6, marker=dict( color='black',             line=dict(color='#000000', width=2 ) ) )

    layout = dict(title =  f'Distribution of {str(col)} feature by Target - With Churn Rates', xaxis=dict(), yaxis=dict(title= 'Count'), yaxis2=dict(range= [0, 100], overlaying= 'y', anchor= 'x', side= 'right', zeroline=False, showgrid= False, title= 'Percentual Churn Ratio' ))

    fig = go.Figure(data=[trace1, trace2, trace3], layout=layout)
    iplot(fig)

def plot_distribution(df, var_select=None, bins=1.0):
    # Calculate the correlation coefficient between the new variable and the target
    tmp_churn = df[df['Churn'] == 1]
    tmp_no_churn = df[df['Churn'] == 0]
    corr = df_train['Churn'].corr(df_train[var_select])
    corr = np.round(corr,3)
    tmp1 = tmp_churn[var_select].dropna()
    tmp2 = tmp_no_churn[var_select].dropna()
    hist_data = [tmp1, tmp2]

    group_labels = ['Yes_churn', 'No_churn']
    colors = ['seagreen','indianred', ]

    fig = ff.create_distplot(hist_data, group_labels, colors = colors, show_hist = True, curve_type='kde', bin_size = bins )

    fig['layout'].update(title = var_select+' '+'(corr target ='+ str(corr)+')')

    iplot(fig, filename = 'Density plot')

def monthly_charges(df, col, binary=None):
    #(df_train.groupby(['Churn', 'tenure'])['MonthlyCharges'].mean()).unstack('Churn').reset_index()
    df_tmp = (df_train.groupby([binary, col])['MonthlyCharges'].mean().reset_index())

    tmp_churn = df_tmp[df_tmp['Churn'] == 1]
    tmp_no_churn = df_tmp[df_tmp['Churn'] == 0]

    df_tmp = (df_train.groupby([binary, col])['MonthlyCharges'].mean()).unstack('Churn').reset_index()
    df_tmp['diff_rate'] = round((df_tmp[1] / df_tmp[0]) - 1,2) * 100

    trace1 = go.Bar( x=tmp_churn[col], y=tmp_churn['MonthlyCharges'], name='Mean Charge\nChurn',opacity = 0.8, marker=dict( color='seagreen',             line=dict(color='#000000',width=1)))

    trace2 = go.Bar( x=tmp_no_churn[col], y=tmp_no_churn['MonthlyCharges'], name='Mean Charge No Churn', opacity = 0.8, marker=dict( color='indianred',             line=dict(color='#000000', width=1) ) )

    trace3 =  go.Scatter( x=df_tmp[col], y=df_tmp['diff_rate'], yaxis = 'y2', name='% Diff Churn', opacity = 0.6, marker=dict( color='black',             line=dict(color='#000000', width=5 ) ) )

    layout = dict(title =  f'Mean Monthly Charges of {str(col)} feature by Churn or Not Churn Customers - With Churn Ratio', xaxis=dict(), yaxis=dict(title= 'Mean Monthly Charges'), yaxis2=dict(range= [0, 100], overlaying= 'y', anchor= 'x', side= 'right', zeroline=False, showgrid= False, title= '% diff Monthly Charges Mean' ))

    fig = go.Figure(data=[trace1, trace2, trace3], layout=layout)
    iplot(fig)

# ## Importing the dataset

# In[ ]:

df_train = pd.read_csv("../../../input/blastchar_telco-customer-churn/WA_Fn-UseC_-Telco-Customer-Churn.csv")

# In[ ]:

def resumetable(df):
    print(f"Dataset Shape: {df.shape}")
    summary = pd.DataFrame(df.dtypes,columns=['dtypes'])
    summary = summary.reset_index()
    summary['Name'] = summary['index']
    summary = summary[['Name','dtypes']]
    summary['Missing'] = df.isnull().sum().values
    summary['Uniques'] = df.nunique().values
    summary['First Value'] = df.loc[0].values
    summary['Second Value'] = df.loc[1].values
    summary['Third Value'] = df.loc[2].values

    for name in summary['Name'].value_counts().index:
        summary.loc[summary['Name'] == name, 'Entropy'] = round(stats.entropy(df[name].value_counts(normalize=True), base=10),2)

    return summary

# In[ ]:

resumetable(df_train)

# Very interesting.

# - We can see that we have one entry for each CustomerId
# - The dataset don't have missing values
# - Some features are categorical
# - The target the we will use to guide the exploration is Churn
#
# ## Let's investigate the data further.
# - I will get all categorical features and see their distribution by the target
# - I will calculate the Churn Rate for each value in categories

# In[ ]:

cat_features = ['gender', 'SeniorCitizen', 'Partner', 'Dependents', 'PaperlessBilling', 'PhoneService', 'Contract', 'StreamingMovies', 'StreamingTV', 'TechSupport', 'OnlineBackup', 'OnlineSecurity', 'InternetService', 'MultipleLines', 'DeviceProtection', 'PaymentMethod']

# ## Understanding the Churn Distribution
# - Let's known our target feature

# In[ ]:

print("CUSTOMERS %CHURN:")
print(round(df_train['Churn'].value_counts(normalize=True) * 100,2))
# df_train.groupby('Churn')['customerID'].count().iplot(kind='bar', title='Churn (Target) Distribution',
#                                                      xTitle='Customer Churn?', yTitle='Count')

trace0 = go.Bar( x=df_train.groupby('Churn')['customerID'].count().index, y=df_train.groupby('Churn')['customerID'].count().values, marker=dict( color=['indianred', 'seagreen']), )

data = [trace0]
layout = go.Layout( title='Churn (Target) Distribution', xaxis=dict( title='Customer Churn?'), yaxis=dict( title='Count') )

fig = go.Figure(data=data, layout=layout)
iplot(fig)

# We have 26.5% of our data that is about the Churned customers, and I will try to understand the pattern of these groups

# I will filter the dataset and set an dataset for Churn and Non Churn Customers.
# - Also, I will see if monthly Charges has some difference to Churn and Non-Churn Customers.

# - I have the hipotesis that maybe Churn customers has a highest mean value of no churn customers

# ## Monthly Charges Distribution
# Let's see the distribution of Monthly Charges by Churn and No Churn Customers.
#

# In[ ]:

df_train['TotalCharges'].fillna(df_train['MonthlyCharges'], inplace=True)
df_train['Churn'] = df_train.Churn.replace({'Yes': 1, 'No': 0})
print(f"The mininum value in Monthly Charges is {df_train['MonthlyCharges'].min()} and the maximum is {df_train['MonthlyCharges'].max()}")
print(f"The mean Monthly Charges of Churn Customers is {round(df_train[df_train['Churn'] != 0]['MonthlyCharges'].mean(),2)}      \nThe mean Monthly Charges of Non-churn Customers is {round(df_train[df_train['Churn'] == 0]['MonthlyCharges'].mean(),2)}")

plot_distribution(df_train, 'MonthlyCharges', bins=4.0)

# - We can see that monthly Charges have a medium correlation with Churn feature.
# - The distribution of Yes and No has clearly different pattern.

# ## Ploting all categorical features

# I will plot all categorical features distributions with the % of Churn by each category and the mean and difference of Monhtly charges for each group

# In[ ]:

## The inspiration of this view is a Kernel that I saw in Vincent Lugat Kernel
## I did some modifications but you can see the original on IBM

for col in cat_features:
    binary_ploting_distributions(df_train, col)

# Analyzing the outputs we can note that:
# - Gender,  PhoneService, MultipleLines don't have a clear difference Churn Rates between the values in categories
# - The other features seems that could be possible to help algorithmn predict Churn Customers
# - The features with the churn ratio values higher or equal to 40%:

# -- Internet service

# -- online Security

# -- online Backup

# -- tech support

# -- contract

# -- seniorcitzen

#
# We can see that in some categories, the churn customers have highest mean of monthly charges.

# ## Understanding the distribution of Total services provided for each Customer and the Churn % Rate

# In[ ]:

df_train['internet']= np.where(df_train.InternetService != 'No', 'Yes', 'No')

df_train['num_services'] = (df_train[['PhoneService', 'OnlineSecurity', 'OnlineBackup', 'DeviceProtection', 'TechSupport', 'StreamingTV', 'StreamingMovies', 'internet']] == 'Yes').sum(axis=1)

# In[ ]:

binary_ploting_distributions(df_train, 'num_services')

# We have 22% of customers with only one service contracted... Of people with 1 service contract, 95% are Phone Service and 5% of total are DSL;
#
# Altought we have some part of our sample with one service, we can see that people with two services are more propense to left.
#
# 100% of Customers with total of services 2+ has internet (DSL or Fiber)

# ## Based on Num Services
# - I thought in see what's the Contract Type and the Churn distribution by each group

# In[ ]:

def countplot(x, hue, **kwargs):
    sns.countplot(x=x, hue=hue, **kwargs, order=['Month-to-month', 'One year', 'Two year'])

print("TOTAL NUMBER OF SERVICES BY CONTRACT AND CHURN")
grid = sns.FacetGrid(data=df_train,col='num_services', col_wrap=2, aspect=1.9, size=3, sharey=False, sharex=False)
fig = grid.map(countplot,'Contract','Churn', palette=['indianred', 'seagreen'] )
fig.set_titles('Customer Total Services: {col_name}', fontsize=18)
fig.add_legend()

print()

# Very cool and meaningful visualization.
#
# We can see difference in Contract feature in different total services that a customer has.

# ## Knowning the Numerical Features
# - The total features is object because it contains blank space.

# - When exploring the dataset, I noted that these values occurs in customers with tenure 0, that don't have generated the first bill.
#

# In[ ]:

df_train.loc[df_train['TotalCharges'] == ' ', 'TotalCharges'] = np.nan
df_train['TotalCharges'] = df_train['TotalCharges'].astype(float)

# - I will fill this Na's values with zero

# ## Total of the Monthly Revenue Lose

# In[ ]:

print("Total Amount of Monthly Charges by each group: ")
print(round(df_train.groupby('Churn')['MonthlyCharges'].sum() ))

trace0 = go.Bar( x=round(df_train.groupby('Churn')['MonthlyCharges'].sum()  / df_train.groupby('Churn')['MonthlyCharges'].sum().sum() * 100).index, y=round(df_train.groupby('Churn')['MonthlyCharges'].sum()  / df_train.groupby('Churn')['MonthlyCharges'].sum().sum() * 100).values, marker=dict( color=['indianred', 'seagreen']), )

data = [trace0]
layout = go.Layout( title='Monthly Revenue % Lost by Churn Customer or not', xaxis=dict( title='Customer Churn?', type='category'), yaxis=dict( title='% of Total Monthly Revenue') )

fig = go.Figure(data=data, layout=layout)
iplot(fig)

# We can see that when we consider the amount of customers, the churn represents 26.5% of total customers, but when we consider Monthly Charges we can see that the ratio is 31% of total revenue was "lost" by people who left.

# ## Distribution of Total Charges
# - To better view the Total Charges I will use the log of Total Charges

# In[ ]:

df_train['TotalCharges_log'] = np.log(df_train['TotalCharges']+1)
print(f"The mininum value in Total Charges is {df_train['TotalCharges'].min()} and the maximum is {df_train['TotalCharges'].max()}")
print(f"The mean Total Charges of Churn Customers is {round(df_train[df_train['Churn'] != 0]['TotalCharges'].mean(),2)}      \nThe mean Total Charges of Non-churn Customers is {round(df_train[df_train['Churn'] == 0]['TotalCharges'].mean(),2)}")

plot_distribution(df_train, 'TotalCharges_log', bins=.25)

# We can note that churn customers has lower values in Total Charges.... I think that it's a signal of a different tenure values;

# Let's check what tenure feature says.

# ## Tenure feature
# - Let's understand the distribution and churn probabilities by Tenure

# In[ ]:

print(f"The mininum value in Tenure is {df_train['tenure'].min()} and the maximum is {df_train['tenure'].max()}")
print(f"The mean Tenure of Churn Customers is {round(df_train[df_train['Churn'] != 0]['tenure'].mean())}      \nThe mean Tenure of Non-churn Customers is {round(df_train[df_train['Churn'] == 0]['tenure'].mean())}")

plot_dist_churn(df_train, 'tenure', 'Churn')

# We can see that the mean of two groups has different... To afirm it, we need to do a statistc test, but it's a very insightful visualization.

# ## Mean Monthly Charges by tenure with Churn Rate of tenure values

# In[ ]:

print("MEAN MONTHLY CHARGES OF TENURE FOR CHURN OR NO CHURN CUSTOMERS")

monthly_charges(df_train, 'tenure', 'Churn')

# Very insightful. The mean of Monthly Charges and the difference Churn Customer is highest in Churn Customers.
# we can see that in tenure 45 months, is the unique
#

# ## The Average Monthly Charges by Total Number of Services Contracted
#

# In[ ]:

monthly_charges(df_train, 'num_services', 'Churn')

#
# Nice! We can see that to customers that has only Phone Services we cannot see difference in average monthly charges.

# In customers with two or more services we can see difference in Average Monthly Charges of Churn Customers to Customers who keep the services

# ## Knowing Tenure by Total Charges for each Target value

# In[ ]:

tmp_churn = df_train[df_train['Churn'] == 1]
tmp_no_churn = df_train[df_train['Churn'] == 0]

tmp_churn_fiber = tmp_churn[tmp_churn['InternetService'] == 'Fiber optic']
tmp_churn_dsl = tmp_churn[tmp_churn['InternetService'] == 'DSL']
tmp_churn_no = tmp_churn[tmp_churn['InternetService'] == 'No']

tmp_no_churn_fiber = tmp_no_churn[tmp_no_churn['InternetService'] == 'Fiber optic']
tmp_no_churn_dsl = tmp_no_churn[tmp_no_churn['InternetService'] == 'DSL']
tmp_no_churn_no = tmp_no_churn[tmp_no_churn['InternetService'] == 'No']

# Create traces
trace0 = go.Scatter( x = tmp_churn_fiber['tenure'], y = tmp_churn_fiber['MonthlyCharges'], mode = 'markers', opacity=.6, name = 'Churn - Fiber', marker=dict( color='indianred', symbol='star' ))
trace1 = go.Scatter( x = tmp_churn_dsl['tenure'], y = tmp_churn_dsl['MonthlyCharges'], mode = 'markers', opacity=.6, name = 'Churn - DSL', marker=dict( color='indianred', symbol='square' ))
trace2 = go.Scatter( x = tmp_churn_no['tenure'], y = tmp_churn_no['MonthlyCharges'], mode = 'markers', opacity=.6, name = 'Churn - No', marker=dict( color='indianred', symbol='circle' ))

# Create traces
trace3 = go.Scatter( x = tmp_no_churn_fiber['tenure'], y = tmp_no_churn_fiber['MonthlyCharges'], mode = 'markers', opacity=.6, name = 'No-Churn-Fiber', marker=dict( color='seagreen', symbol='star' ))
trace4 = go.Scatter( x = tmp_no_churn_dsl['tenure'], y = tmp_no_churn_dsl['MonthlyCharges'], mode = 'markers', opacity=.6, name = 'No-Churn-DSL', marker=dict( color='seagreen', symbol='square' ))
trace5 = go.Scatter( x = tmp_no_churn_no['tenure'], y = tmp_no_churn_no['MonthlyCharges'], mode = 'markers', opacity=.6, name = 'No-Churn-No', marker=dict( color='seagreen', symbol='circle' ))

layout = dict(title ='Dispersion of Total Charges explained by Monthly Charges by Target', xaxis=dict(title='Internet Service Types'), yaxis=dict(title= 'Monthly Charges'))

fig = go.Figure(data = [trace0, trace3, trace1, trace4, trace2, trace5], layout=layout)
iplot(fig)

# We can clearly see a "linear function" where the two features are very correlated and it that make a lot of sense.

# I tought that could be interesting if we divide the Total charges by the Monthly Charges and we will get the months till the Churn... It would be very close value of tenure

# In[ ]:

df_train['assign_months'] = round(df_train['TotalCharges'] / df_train['MonthlyCharges'],0)

# In[ ]:

print("Comparing Tenure and Assign Months")
pd.concat([df_train['assign_months'].describe().reset_index(), df_train['tenure'].describe().reset_index()['tenure']], axis=1)

# Cool.
# As we can see, the both features shows the same information, so I will drop the new features that I created

# In[ ]:

df_train.drop('assign_months', axis=1, inplace=True)

# ## Mean Monthly Charges by Categorical Features and the Diff Ratio of Charges

# ## Let's see the Ratio of Revenue lost by some interesting Features
# - This charts shows the

# In[ ]:

def PieChart(df_cat, df_value, title, limit=15):
    """ This function helps to investigate the proportion of metrics of toxicity and other values """

    # count_trace = df_train[df_cat].value_counts()[:limit].to_frame().reset_index()
    tmp_churn = df_train[df_train['Churn'] == 1].groupby(df_cat)[df_value].sum().nlargest(limit).to_frame().reset_index()
    tmp_no_churn = df_train[df_train['Churn'] == 0].groupby(df_cat)[df_value].sum().nlargest(limit).to_frame().reset_index()

    trace1 = go.Pie(labels=tmp_no_churn[df_cat], values=tmp_no_churn[df_value], name= "No-Churn", hole= .5, hoverinfo="label+percent+name+value", showlegend=True, domain= {'x': [0, .48]})

    trace2 = go.Pie(labels=tmp_churn[df_cat], values=tmp_churn[df_value], name="Churn", hole= .5, hoverinfo="label+percent+name+value", showlegend=False, domain= {'x': [.52, 1]})

    layout = dict(title= title, height=450, font=dict(size=15), annotations = [ dict( x=.20, y=.5, text='No Churn', showarrow=False, font=dict(size=20) ), dict( x=.80, y=.5, text='Churn', showarrow=False, font=dict(size=20) ) ])

    fig = dict(data=[trace1, trace2], layout=layout)
    iplot(fig)

# ## %Ratio of Monthly Charges by Internet Service
# For instance:

# Optical fiber is responsible for 53% (168,99k) of the monthly revenue, DSL 37% (118,14k) and 9% of customers don't have

# In[ ]:

no_churn_monthly_renenue = tmp_no_churn['MonthlyCharges'].sum()

# In[ ]:

PieChart("InternetService", 'MonthlyCharges', "Internet Services Total Charges by Churn", limit=10)

#

# ## %Ratio of Monthly Charges by Contract types

# In[ ]:

PieChart("Contract", 'MonthlyCharges', "Type of Contract by Churn or not with Ratio of Monthly Charges", limit=10)

# Nice. 87% of all monthly revenue lost are caused by customers with Month-to-Month Contracts
# - As we can see in some graphs, Contract has a lot of informations about the Churn and it could help us to predict.

# ## %Ratio of Monthly Charges by Multiple Lines

# In[ ]:

PieChart("MultipleLines", 'MonthlyCharges', "Type of Contract by Churn or not with Ratio of Monthly Charges", limit=10)

# ## %Ratio of Monthly Charges by Device Protection

# In[ ]:

PieChart("DeviceProtection", 'MonthlyCharges', "Type of Contract by Churn or not with Ratio of Monthly Charges", limit=10)

# ## %Ratio of Monthly Charges by Tech Support

# In[ ]:

PieChart("TechSupport", 'MonthlyCharges', "Type of Contract by Churn or not with Ratio of Monthly Charges", limit=10)

# ## %Ratio of Monthly Charges by Online Backup
#

# In[ ]:

PieChart("OnlineBackup", 'MonthlyCharges', "Type of Contract by Churn or not with Ratio of Monthly Charges", limit=10)

# ## %Ratio of Monthly Charges by Online Security

# In[ ]:

PieChart("OnlineSecurity", 'MonthlyCharges', "Type of Contract by Churn or not with Ratio of Monthly Charges", limit=10)

# In[ ]:

# ## Based on the plots, let's create some binary features and see the distributions again

# ## Feature engineering and preprocessing

# In[ ]:

Id_col     = ['customerID']

target_col = ["Churn"]

cat_cols   = df_train.nunique()[df_train.nunique() < 10].keys().tolist()
cat_cols   = [x for x in cat_cols if x not in target_col]
binary_cols   = df_train.nunique()[df_train.nunique() == 2].keys().tolist()

multi_cols = [i for i in cat_cols if i not in binary_cols]

# ## Feature Engineering

# In[ ]:

df_train.loc[:,'Engaged'] = np.where(df_train['Contract'] != 'Month-to-month', 1,0)
df_train.loc[:,'YandNotE'] = np.where((df_train['SeniorCitizen']==0) & (df_train['Engaged']==0), 1,0)
df_train.loc[:,'ElectCheck'] = np.where((df_train['PaymentMethod'] == 'Electronic check') & (df_train['Engaged']==0), 1,0)
df_train.loc[:,'fiberopt'] = np.where((df_train['InternetService'] != 'Fiber optic'), 1,0)
df_train.loc[:,'StreamNoInt'] = np.where((df_train['StreamingTV'] != 'No internet service'), 1,0)
df_train.loc[:,'NoProt'] = np.where((df_train['OnlineBackup'] != 'No') |                                    (df_train['DeviceProtection'] != 'No') |                                    (df_train['TechSupport'] != 'No'), 1,0)

df_train['TotalServices'] = (df_train[['PhoneService', 'InternetService', 'OnlineSecurity', 'OnlineBackup', 'DeviceProtection', 'TechSupport', 'StreamingTV', 'StreamingMovies']]== 'Yes').sum(axis=1)

# In[ ]:

from sklearn.preprocessing import LabelEncoder

#Label encoding Binary columns
le = LabelEncoder()

tmp_churn = df_train[df_train['Churn'] == 1]
tmp_no_churn = df_train[df_train['Churn'] == 0]

bi_cs = df_train.nunique()[df_train.nunique() == 2].keys()
dat_rad = df_train[bi_cs]

for cols in bi_cs :
    tmp_churn[cols] = le.fit_transform(tmp_churn[cols])

data_frame_x = tmp_churn[bi_cs].sum().reset_index()
data_frame_x.columns  = ["feature","yes"]
data_frame_x["no"]    = tmp_churn.shape[0]  - data_frame_x["yes"]
data_frame_x  = data_frame_x[data_frame_x["feature"] != "Churn"]

#count of 1's(yes)
trace1 = go.Scatterpolar(r = data_frame_x["yes"].values.tolist(), theta = data_frame_x["feature"].tolist(), fill  = "toself",name = "Churn 1's", mode = "markers+lines", visible=True, marker = dict(size = 5) )

#count of 0's(No)
trace2 = go.Scatterpolar(r = data_frame_x["no"].values.tolist(), theta = data_frame_x["feature"].tolist(), fill  = "toself",name = "Churn 0's", mode = "markers+lines", visible=True, marker = dict(size = 5) )
for cols in bi_cs :
    tmp_no_churn[cols] = le.fit_transform(tmp_no_churn[cols])

data_frame_x = tmp_no_churn[bi_cs].sum().reset_index()
data_frame_x.columns  = ["feature","yes"]
data_frame_x["no"]    = tmp_no_churn.shape[0]  - data_frame_x["yes"]
data_frame_x  = data_frame_x[data_frame_x["feature"] != "Churn"]

#count of 1's(yes)
trace3 = go.Scatterpolar(r = data_frame_x["yes"].values.tolist(), theta = data_frame_x["feature"].tolist(), fill  = "toself",name = "NoChurn 1's", mode = "markers+lines", visible=False, marker = dict(size = 5) )

#count of 0's(No)
trace4 = go.Scatterpolar(r = data_frame_x["no"].values.tolist(), theta = data_frame_x["feature"].tolist(), fill  = "toself",name = "NoChurn 0's", mode = "markers+lines", visible=False, marker = dict(size = 5) )

data = [trace1, trace2, trace3, trace4]

updatemenus = list([ dict(active=0, x=-0.15, buttons=list([ dict( label = 'Churn Dist', method = 'update', args = [{'visible': [True, True, False, False]}, {'title': 'Customer Churn Binary Counting Distribution'}]),  dict( label = 'No-Churn Dist', method = 'update', args = [{'visible': [False, False, True, True]}, {'title': 'No Customer Churn Binary Counting Distribution'}]),  ]), ) ])

layout = dict(title='ScatterPolar Distribution of Churn and Non-Churn Customers (Select from Dropdown)', showlegend=False, updatemenus=updatemenus)

fig = dict(data=data, layout=layout)

iplot(fig)

# Nice, we can easily access a lot of information about our customers.
#

# # Creating new numerical columns

# In[ ]:

multi_cols.remove('Contract')
df_train['monthly_diff_mean'] = df_train['MonthlyCharges'] / df_train['MonthlyCharges'].mean()
for cat in cat_cols:
    df_train[str(cat)+'_diff_mean'] = df_train['MonthlyCharges'] / df_train.groupby(['Contract',cat])['MonthlyCharges'].transform('mean')
    df_train[str(cat)+'_diff_std'] = df_train['MonthlyCharges'] / df_train.groupby(['Contract',cat])['MonthlyCharges'].transform('std')

# ## Encoding and binarizing features

# In[ ]:

for cols in binary_cols :
    df_train[cols] = le.fit_transform(df_train[cols])

#Duplicating columns for multi value columns
df_train = pd.get_dummies(data = df_train,columns = multi_cols )

df_train.drop("Contract", axis=1, inplace=True)

# In[ ]:

num_cols   = [x for x in df_train.columns if x not in cat_cols + target_col + Id_col]

from sklearn.preprocessing import StandardScaler
df_train.fillna(-99, inplace=True)
#Scaling Numerical columns
ss = StandardScaler()
scl = ss.fit_transform(df_train[num_cols])
scl = pd.DataFrame(scl, columns=num_cols)

#dropping original values merging scaled values for numerical columns
# df_data_og = df_train.copy()

df_train = df_train.drop(columns = num_cols,axis = 1)
df_train = df_train.merge(scl, left_index=True, right_index=True, how = "left")

# ## Feature Selection
# - Let's use the correlation to drop features high correlation

# In[ ]:

# Threshold for removing correlated variables
threshold = 0.90

# Absolute value correlation matrix
corr_matrix = df_train.corr().abs()

# Getting the upper triangle of correlations
upper = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(np.bool))

# In[ ]:

# Select columns with correlations above threshold
to_drop = [column for column in upper.columns if any(upper[column] > threshold)]

print('There are %d columns to remove.' % (len(to_drop)))
print(list(to_drop))

# In[ ]:

df_train = df_train.drop(columns = to_drop)
print('Training shape: ', df_train.shape)

# ## Preprocessing - Seting X and y
# - spliting into X_train and X_val

# In[ ]:

from sklearn.model_selection import train_test_split
X_train = df_train.drop(['Churn', 'customerID'], axis=1)
y_train = df_train['Churn']

# In[ ]:

X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=.20)

# ## Classifier models pipeline

# In[ ]:

clfs = []
seed = 3

clfs.append(("LogReg", Pipeline([("Scaler", StandardScaler()), ("LogReg", LogisticRegression())])))

clfs.append(("XGBClassifier", Pipeline([("Scaler", StandardScaler()), ("XGB", XGBClassifier())])))
clfs.append(("KNN", Pipeline([("Scaler", StandardScaler()), ("KNN", KNeighborsClassifier())])))

clfs.append(("DecisionTreeClassifier", Pipeline([("Scaler", StandardScaler()), ("DecisionTrees", DecisionTreeClassifier())])))

clfs.append(("RandomForestClassifier", Pipeline([("Scaler", StandardScaler()), ("RandomForest", RandomForestClassifier())])))

clfs.append(("GradientBoostingClassifier", Pipeline([("Scaler", StandardScaler()), ("GradientBoosting", GradientBoostingClassifier(max_features=15, n_estimators=1000))])))

clfs.append(("RidgeClassifier", Pipeline([("Scaler", StandardScaler()), ("RidgeClassifier", RidgeClassifier())])))

clfs.append(("BaggingRidgeClassifier", Pipeline([("Scaler", StandardScaler()), ("BaggingClassifier", BaggingClassifier())])))

clfs.append(("ExtraTreesClassifier", Pipeline([("Scaler", StandardScaler()), ("ExtraTrees", ExtraTreesClassifier())])))

#'neg_mean_absolute_error', 'neg_mean_squared_error','r2'
scoring = 'accuracy'
n_folds = 10

results, names  = [], []

for name, model  in clfs:
    kfold = KFold(n_splits=n_folds, random_state=seed)
    cv_results = cross_val_score(model, X_train, y_train, cv=kfold, scoring=scoring, n_jobs=-1)
    names.append(name)
    results.append(cv_results)
    msg = "%s: %f (+/- %f)" % (name, cv_results.mean(), cv_results.std())
    print(msg)

# boxplot algorithm comparison
fig = plt.figure(figsize=(15,6))
fig.suptitle('Classifier Algorithm Comparison', fontsize=22)
ax = fig.add_subplot(111)
sns.boxplot(x=names, y=results)
ax.set_xticklabels(names)
ax.set_xlabel("Algorithmn", fontsize=20)
ax.set_ylabel("Accuracy of Models", fontsize=18)
ax.set_xticklabels(ax.get_xticklabels(),rotation=45)

print()

#

# In[ ]:

#MODEL FUNCTION

from sklearn.metrics import classification_report,confusion_matrix,accuracy_score,roc_curve,auc

def model(algorithm, X_train, y_train,
          X_val, y_val, of_type):

    print ("*****************************************************************************************")
    print ("MODEL - OUTPUT")
    print ("*****************************************************************************************")
    algorithm.fit(X_train.values,y_train.values)
    predictions = algorithm.predict(X_val.values)

    print ("\naccuracy_score :",accuracy_score(y_val, predictions))

    print ("\nclassification report :\n",(classification_report(y_val, predictions)))

    plt.figure(figsize=(14,12))
    plt.subplot(221)
    print()

    plt.title("CONFUSION MATRIX",fontsize=20)

    predicting_probabilites = algorithm.predict_proba(X_val)[:,1]
    fpr,tpr,thresholds = roc_curve(y_val,predicting_probabilites)
    plt.subplot(222)
    plt.plot(fpr,tpr,label = ("Area_under the curve :",auc(fpr,tpr)),color = "r")
    plt.plot([1,0],[1,0],linestyle = "dashed",color ="k")
    plt.legend(loc = "best")
    plt.title("ROC - CURVE & AREA UNDER CURVE",fontsize=20)

    if  of_type == "feat":

        dataframe = pd.DataFrame(algorithm.feature_importances_, X_train.columns).reset_index()
        dataframe = dataframe.rename(columns={"index":"features",0:"coefficients"})
        dataframe = dataframe.sort_values(by="coefficients",ascending = False)
        plt.subplot(224)
        ax = sns.barplot(x = "coefficients" ,y ="features",data=dataframe,palette="husl")
        plt.title("FEATURE IMPORTANCES",fontsize =20)
        for i,j in enumerate(dataframe["coefficients"]):
            ax.text(.011,i,j,weight = "bold")

    elif of_type == "coef" :

        dataframe = pd.DataFrame(algorithm.coef_.ravel(),X_train.columns).reset_index()
        dataframe = dataframe.rename(columns={"index":"features",0:"coefficients"})
        dataframe = dataframe.sort_values(by="coefficients",ascending = False)
        plt.subplot(224)
        ax = sns.barplot(x = "coefficients" ,y ="features",data=dataframe,palette="husl")
        plt.title("FEATURE IMPORTANCES",fontsize =20)
        for i,j in enumerate(dataframe["coefficients"]):
            ax.text(.011,i,j,weight = "bold")

    elif of_type == "none" :
        return (algorithm)

# ## Logistic Regression Prediction and Feature Importance

# In[ ]:

rf =LogisticRegression(solver = "lbfgs", multi_class = "auto")

model(rf,X_train, y_train, X_val, y_val, "coef")

# ## XGBClassifier

# In[ ]:

xgb = XGBClassifier(n_estimators=800, n_jobs=-1)

xgb.fit(X_train.values,y_train.values)
predictions = xgb.predict(X_val.values)

print ("\naccuracy_score :",accuracy_score(y_val, predictions))

print ("\nclassification report :\n",(classification_report(y_val, predictions)))

plt.figure(figsize=(14,12))
plt.subplot(221)
print()

plt.title("CONFUSION MATRIX",fontsize=20)

# ## Random Forest Model and Feature Importances

# In[ ]:

rf =RandomForestClassifier(n_estimators=500)

model(rf,X_train, y_train, X_val, y_val, "feat")

# In[ ]:

# In[ ]:

# # NOTE: This kernel is not finished. If you think that it's useful, votes up the kernel


a=[]
n=int(input('enter the length of the list \n'))
def add_values(value,index,li):
    li.insert(index,value)

def max_elemnt(b):
    max_el=b[0]
    for i in range(1,len(b)):
        if b[i]>max_el :
            max_el=b[i]

    return print(f"is the largest elemnt of the list {max_el}")

for i in range(0,n):
    x=int(input(f"enter the values to the list {a}\n"))
    add_values(x,i,a)
    if(i==n-1):
        choice=str(input("if want to print max elment Y-yes N-no\n"))
        if choice=='Y' or choice=='y':
            max_elemnt(a)
        elif choice=='N' or choice=='n':
            print(' ')
        else:
            print("in valid entry")


import cv2
from service import label_service

MIN_VERTICIES = 10
MAX_VERTICIES = 40
MIN_AREA = 1000
MAX_AREA= 5000

class ShapeDetector:
    def __init__(self):
        pass

    def detect_verticies(self, contour):
        perimeter = cv2.arcLength(contour, True)

        # 0.01 - 0.05
        percent = 0.004

        verticies = cv2.approxPolyDP(contour, percent * perimeter, True)

        return verticies

    def is_puzzle(self, contour):
        verticies = self.detect_verticies(contour)
        num_verticies = len(verticies)

        if num_verticies < MIN_VERTICIES or num_verticies > MAX_VERTICIES:
            return False

        area = cv2.contourArea(contour)
        if area < MIN_AREA or area > MAX_AREA:
            return False

        return True


"""
Enunciado: Leia o salário de um trabalhador e o valor da prestação de um empréstimo.
Se a prestação for maior que 20% do salário imprima: Empréstimo não concedido, caso
contrário imprima: Empréstimo concedido.

Resolução:
"""

num1 = int(input("Insert your salary: "))

num2 = int(input("Insert installment amount: "))

print("Loan not granted." if num2 > (num1 * 0.2) else "Loan granted.")

"""
Comentário: A resolução do código consistiu na coleta das informações e retorno do
resultado das operações.
"""


picture = [
[0,0,0,1,0,0,0],
[0,0,1,1,1,0,0],
[0,1,1,1,1,1,0],
[1,1,1,1,1,1,1],
[0,0,0,1,0,0,0],
[0,0,0,1,0,0,0]
]

#  iterate
# if 0 print ''
# if 1 print *
fill = "*"
empty = ' '
for row in picture:
    for pixel in row:
        if pixel == 0:
            print(empty , end='')
        elif pixel == 1:
            print(fill ,end='')
    print(' ') # need a new line after every row
# developer fundamentals
# clean
# readibility

# find duplicates
# execise check for duplicates
some_list = ['a','b','c','b','d','m','n','n']
duplicate = []
for i in some_list:
    if some_list.count(i) > 1:
        if i not in duplicate:
            duplicate.append(i)
print(duplicate)


import sqlite3
import DatabaseLogicProduct
import DatabaseQuery
import random
import DatabaseLogicJobs
import DatabaseLogicMarket
import DatabaseLogicStat
import KeybordClass
import DatabaseLogicReferalCode

class DBAdminPanelClass:
    db = DatabaseQuery.MainDatabaseQuery()
    NS = KeybordClass.NameSpace()
    queryCreate = "CREATE TABLE admin(id integer, uname text)"
    queryCreateRefAdmin = "CREATE TABLE adminRef(key integer, rights integer)"
    queryCheckAdmin = "SELECT * FROM admin WHERE id = {}"
    queryName = "SELECT uname FROM admin WHERE id = {}"
    queryAddAdmin = "INSERT INTO admin VALUES({},'{}',{})"
    queryRightsRefCode = "SELECT rights FROM adminRef WHERE key = {}"
    queryAdminRefCode = "SELECT key FROM adminRef WHERE key = {}"
    queryCheckAdminRights = "SELECT rights FROM admin WHERE id = {}"
    queryNametoID = "SELECT id FROM admin WHERE uname = '{}'"
    queryAllAdminPush = "SELECT id FROM admin"
    queryInsertAdminRefCode = "INSERT INTO adminRef VALUES({},{})"
    queryCountAdmin = "SELECT * FROM admin"
    queryRightsName = "SELECT rights FROM admin WHERE uname = '{}'"
    queryDelete = "DELETE FROM adminRef"
    queryDeleteAdmin = "DELETE FROM admin WHERE id = {}"
    queryAlready = "SELECT * FROM admin"
    queryCheckName = "SELECT * FROM admin where uname = '{}'"
    queryAllAdmin = "SELECT id, uname, rights FROM admin"
    def isAdmin(self, id):
        query = self.queryCheckAdmin.format(id)
        row = self.db.queryAndAnswerDB(query)
        return len(row) > 0
    def isName(self, id):
        query = self.queryName.format(id)
        row = self.db.queryAndAnswerDB(query)
        if(len(row) > 0):
            return row[0][0]
        return False
    def exportDB(self):
        file = open('sqlitedb.db', 'rb')
        return file
    def checkAlready(self):
        query = self.queryAlready
        row = self.db.queryAndAnswerDB(query)
        if(len(row) == 0):
            return True
        return False
    def checkName(self,name):
        try:
            userName = str(name)
        except:
            return False
        query = self.queryCheckName.format(userName)
        row = self.db.queryAndAnswerDB(query)
        return len(row) > 0
    def addDefaultAdmin(self,message):
        id = message.from_user.id
        name = message.chat.username
        query = self.queryAddAdmin.format(id, name, 0)
        self.db.queryDB(query)
    def welcome(self, id):
        if (self.isAdmin(id)):
            return self.NS.ANSWER_ADMIN_WELCOME.format(self.isName(id))

    def stateJoinActivate(self):
        db = DatabaseLogicStat.DBStat()
        answer = db.joinStat()
        return answer

    def stateRefActivate(self):
        db = DatabaseLogicReferalCode.MainDBClass()
        answer = db.countActivate()
        return answer

    def stateAll(self):
        dbProduct = DatabaseLogicProduct.DBProductClass()
        dbJob = DatabaseLogicJobs.DBJobClass()
        dbMarket = DatabaseLogicMarket.DBMarketClass()
        statMarket = dbMarket.countForStat()
        stateJoin = self.stateJoinActivate()
        stateRefActivate = self.stateRefActivate()
        statProduct = dbProduct.countProduct()
        stateCountAdmin = len(self.db.queryAndAnswerDB(self.queryCountAdmin))
        stateJobs = dbJob.getID()
        answer = self.NS.ANSWER_ADMIN_STAT.format(stateCountAdmin, stateJoin, stateRefActivate, stateJobs,statMarket[0],statMarket[1],statProduct)
        return answer
    def generateCode(self):
        return random.randint(10000,50000)
    def generateAdminRefCode(self, rights):
        if not len(rights) > 0:
            return
        id = self.generateCode()
        self.db.queryDB(self.queryInsertAdminRefCode.format(id,rights))
        return id

    def checkRights(self, id):
        row = self.db.queryAndAnswerDB(self.queryCheckAdminRights.format(id))
        if len(row) > 0:
            return row[0][0]
        return None
    def selfRights(self, id):
        print(id)
        rights = self.checkRights(id)
        print(rights)
        if rights == 2:
            print("start two")
            return "Вы гость.\n{} уровень доступа\n\nВам доступно только чтение информации.".format(rights)
        elif rights == 1:
            print("start one")
            return "Вы модератор.\n{} уровень доступа\n\nВам доступно чтение и изменение информации. Вы модете добавить пользователя уровня Гость(2 уровень)".format(rights)
        elif rights == 0:
            print("start zero")
            return "Вы администратор проекта.\n{} уровень доступа\n\nВы имеете все права администратора, считаетесь освнователем проекта, вам доступен весь функционал.".format(rights)
        if rights == False:
            print("start false")
            return "Ошибка. Не удалось найти ваши права"
    def isAlreadyAdminRefCode(self,key):
        query = self.queryAdminRefCode.format(key)
        print(query)
        row = self.db.queryAndAnswerDB(query)
        return len(row) > 0
    def addAdmin(self,message,key):
        if(not self.isAlreadyAdminRefCode(key) or self.isAdmin(message.from_user.id)):
            return False
        else:
            queryKey = self.queryRightsRefCode.format(key)
            id = message.from_user.id
            name = message.chat.username
            rights = self.db.queryAndAnswerDB(queryKey)[0][0]
            self.db.queryDB(self.queryAddAdmin.format(id, name, rights))
            self.db.queryDB(self.queryDelete)
            return True
    def adminNametoID(self,keyName):
        query = self.queryNametoID.format(keyName)
        print("query = {}",query)
        row = self.db.queryAndAnswerDB(query)
        print("adminNamtoID return {}",row[0][0])
        if len(row) > 0:
            return row[0][0]
        return "No data"
    def adminList(self):
        query = self.queryCountAdmin
        row = self.db.queryAndAnswerDB(query)
        list = "\n"
        for i in row:
            list += "Имя {} | Уровень доступа {}\n".format(i[1], i[2])
        return list
    def adminListMinimal(self):
        query = self.queryCountAdmin
        row = self.db.queryAndAnswerDB(query)
        list = []
        print(row)
        for i in row:
            print(i[1])
            list.append(i[1])
        list.append("ОТМЕНА")
        return list
    def nameToRights(self,keyName):
        query = self.queryRightsName.format(keyName)
        row = self.db.queryAndAnswerDB(query)
        if len(row) > 0:
            return row[0][0]
        return "No data"
    def deleteAdmin(self,selfid,id):
        print("мой id = {}\n id удаляемого - {}".format(selfid,id))
        rightDelete = self.checkRights(id)
        selfRight = self.checkRights(selfid)
        if selfRight == 2:
            return False
        elif selfRight == 1 and rightDelete == 2:
            self.db.queryDB(self.queryDeleteAdmin.format(id))
            return True
        elif selfRight == 0:
            self.db.queryDB(self.queryDeleteAdmin.format(id))
            return True
    def writeListAdminAll(self):
        list = []
        query = self.queryAllAdminPush
        row = self.db.queryAndAnswerDB(query)
        for item in row:
            list.append(item[0])

        return list
    def allAdmin(self):
        query = "SELECT uname, rights FROM admin"
        row = self.db.queryAndAnswerDB(query)
        if not len(row) > 0:
            return "Список пуст."
        answer = ""
        for admin in row:
            name = admin[0]
            if name == "None": name = "Нет Никнейма"
            else:
                name = "@"+admin[0]
            answer += "📂 {} - {} уровень\n".format(name,admin[1])
        return answer
    def adminList(self):
        row = self.db.queryAndAnswerDB(self.queryAllAdmin)
        if len(row) > 0:
            return row
        else:
            return 0
    def onlyAllRights(self):
        list = []
        admin = self.db.queryAndAnswerDB("SELECT id FROM admin WHERE rights = 0")
        for id in admin:
            list.append(id[0])
        return list


# tokens are passed from JackTokenizer -> JackCompiler -> CompilationEngine
# CompilationEngine calls write functions of VMWriter module to write VM instructions

import SymbolTable                  # keeps track of class-scope and subroutine-scope symbols (field, static, local, argument)
import VMWriter                     # writes VM instructions to each .vm file

current_token_number = 0            # allow program to march through list of tokens
tokens = []                         # tokens received from tokenizer (used as global variable)
class_name = ""                     # global class name

global_while_index = -1             # allow unique WHILE labels when generating whileStatements
global_if_index = -1                # allow unique IF labels when generating ifStatements

def compileTokens(token_list, input_class): # called by JackCompiler, passing in current list of tokens and current class
    print("---COMPILING TOKENS---")

    SymbolTable.startClass()        # resets symbol table for class and subroutine, as well as indices

    global tokens, current_token_number, class_name

    current_token_number = 0        # reset; because there are multiple .jack files, thus
    tokens = token_list             # compileTokens will be called multiple times
    class_name = input_class        # current class being compiled

    compile_class()                 # every .jack file begins with class declaration

    print("---DONE COMPILING TOKENS---")

def compile_class():                # class className { classVarDec* subroutineDec* }
    print("---COMPILING CLASS---")

    advance()                       # class
    advance()                       # className
    advance()                       # {

    while (get_current_token() in ["static", "field"]): # check if any classVarDec to parse
        compile_classVarDec()

    while (get_current_token() in ["constructor", "function", "method"]):   # check if any subroutineDec to parse
        compile_subroutine()

    print("---DONE COMPILING CLASS---")

def compile_classVarDec():          # (static | field) type varName (, varName)* ;
    print("---COMPILING CLASS VAR DEC")

    var_kind = get_and_advance()    # static / field
    var_type = get_and_advance()    # type; defined only once per classVarDec
    var_name = get_and_advance()    # varName

    SymbolTable.define(var_name, var_type, var_kind)

    while (get_current_token() != ";"): # field int x, y;
        advance()
        var_name = get_and_advance()
        SymbolTable.define(var_name, var_type, var_kind)

    advance()                       # ;

    print("---DONE COMPILING CLASS---")

def compile_subroutine():           # (constructor | function | method) (void | type) subroutineName
    print("---COMPILING SUBROUTINE---")

    SymbolTable.startSubroutine()   # resets subroutine-scope variables (local, argument)

    subroutine_kind = get_and_advance()     # constructor | function | method
    advance()                               # void | type
    subroutine_name = get_and_advance()     # subroutineName

    if subroutine_kind == "method":
        SymbolTable.define("this", get_class_name(), "argument")

    advance()                       # (
    compile_parameterList()
    advance()                       # )

    advance()                       # {

    while get_current_token() == "var":
        compile_varDec()

    function_name = get_class_name() + "." + subroutine_name
    num_locals = SymbolTable.varCount("local")
    VMWriter.writeFunction(function_name, num_locals)

    if subroutine_kind == "constructor":
        num_fields = SymbolTable.varCount("field")  # get number of field (instance) variables declared in current subroutine
        VMWriter.writePush("constant", num_fields)
        VMWriter.writeCall("Memory.alloc", 1)       # call Memory.alloc, after pushing the number onto the stack
        VMWriter.writePop("pointer", 0)             # store pointer returned in pointer 0
    elif subroutine_kind == "method":
        VMWriter.writePush("argument", 0)
        VMWriter.writePop("pointer", 0)

    compile_statements()
    advance()                       # }

    print("---DONE COMPILING SUBROUTINE---")

def compile_parameterList():        # (type varName (, type varName)*)?
    print("---COMPILING PARAMETER LIST---")

    if get_current_token() != ")":
        var_type = get_and_advance()
        var_name = get_and_advance()

        SymbolTable.define(var_name, var_type, "argument")

    while (get_current_token() != ")"):     # new(int Ax, int Ay, ...)
        advance()                   # ,

        var_type = get_and_advance()
        var_name = get_and_advance()

        SymbolTable.define(var_name, var_type, "argument")

    print("---DONE COMPILING PARAMETER LIST---")

def compile_varDec():               # var type varName (, varName)* ;
    print("---COMPILING VAR DEC---")
    advance()
    var_type = get_and_advance()    # defined only once per varDec
    var_name = get_and_advance()

    SymbolTable.define(var_name, var_type, "local")

    while (get_current_token() != ";"):     # var int dx, dy, dz
        advance()
        var_name = get_and_advance()

        SymbolTable.define(var_name, var_type, "local")

    advance()                       # ;

    print("---DONE COMPILING VAR DEC---")

def compile_statements():           # statement*
    print("---COMPILING STATEMENTS---")
    token = ""

    while (get_current_token() in ["let", "if", "while", "do", "return"]):
        token = get_and_advance()

        if token == "let":
            compile_letStatement()
        elif token == "if":
            compile_ifStatement()
        elif token == "while":
            compile_whileStatement()
        elif token == "do":
            compile_doStatement()
        elif token == "return":
            compile_returnStatement()

    print("---DONE COMPILING STATEMENTS---")

def compile_doStatement():          # do subroutineCall ;
    print("---COMPILING DO STATEMENT---")

    compile_subroutineCall()        # subroutineCall
    VMWriter.writePop("temp", 0)
    advance()

    print("---DONE COMPILING DO STATEMENT---")

def compile_letStatement():         # let varName ([ expression ])? = expression;
    print("---COMPILING LET STATEMENT---")

    var_name = get_and_advance()    # varName
    var_kind = convert_kind(SymbolTable.kindOf(var_name))
    var_index = SymbolTable.indexOf(var_name)

    if (get_current_token() == "["):    # varName '[]' MUST represent an array indexing
        advance()                       # [ expression ]
        compile_expression()
        advance()

        VMWriter.writePush(var_kind, var_index)
        VMWriter.writeArithmetic("add")

        VMWriter.writePop("temp", 0)

        advance()                   # =
        compile_expression()
        advance()                   # ;

        VMWriter.writePush("temp", 0)
        VMWriter.writePop("pointer", 1)
        VMWriter.writePop("that", 0)
    else:
        advance()                   # =
        compile_expression()
        advance()                   # ;

        VMWriter.writePop(var_kind, var_index)

    print("---DONE COMPILING LET STATEMENT---")

def compile_whileStatement():       # while ( expression ) { statements }
    print("---COMPILING WHILE STATEMENT---")

    global global_while_index
    global_while_index += 1

    while_index = global_while_index    # local var used; ensure while_index consistent throughout this function
                                        # global_while_index may be changed by other functions without you knowing

    VMWriter.writeLabel("WHILE_EXP" + str(while_index))         # label WHILE_1

    advance()                       # (
    compile_expression()            # expression
    VMWriter.writeArithmetic("not") # NOT expression
    advance()                       # )
    advance()                       # {

    VMWriter.writeIfGoto("WHILE_END" + str(while_index))    # if-goto WHILE_END_1
    compile_statements()
    VMWriter.writeGoto("WHILE_EXP" + str(while_index))          # goto WHILE_1

    VMWriter.writeLabel("WHILE_END" + str(while_index))
    advance()                       # }

    print("---DONE COMPILING WHILE STATEMENT---")

def compile_returnStatement():              # return expression? ;
    print("---COMPILING RETURN STATEMENT---")

    if (get_current_token() != ";"):        # there must be an expression if current token is not ';'
        compile_expression()                # push return value of expression onto stack
    else:
        VMWriter.writePush("constant", 0)   # if void function, push constant 0

    VMWriter.writeReturn()
    advance()                               # ;

    print("---DONE COMPILING RETURN STATEMENT---")

def compile_ifStatement():          # if ( expression ) { statements }
    print("---COMPILING IF STATEMENT---")

    global global_if_index
    global_if_index += 1

    if_index = global_if_index      #

    advance()                       # ( expression )
    compile_expression()
    advance()

    advance()                       # {

    VMWriter.writeIfGoto("IF_TRUE" + str(if_index))
    VMWriter.writeGoto("IF_FALSE" + str(if_index))

    VMWriter.writeLabel("IF_TRUE" + str(if_index))
    compile_statements()
    VMWriter.writeGoto("IF_END" + str(if_index))

    advance()                       # }

    VMWriter.writeLabel("IF_FALSE" + str(if_index))

    if (get_current_token() == "else"):
        advance()                   # else
        advance()                   # { statements }
        compile_statements()
        advance()

    VMWriter.writeLabel("IF_END" + str(if_index))

def compile_expression():           # term (op term)*
    print("---COMPILING EXPRESSION---")
    compile_term()                  # term

    while (get_current_token() in operator_list):   # an operator has been spotted!
        op = get_and_advance()      # op
        compile_term()              # term

        if op in ARITHMETIC.keys():
            VMWriter.writeArithmetic(ARITHMETIC[op])
        elif op == "*":
            VMWriter.writeCall("Math.multiply", 2)
        elif op == "/":
            VMWriter.writeCall("Math.divide", 2)

    print("---DONE COMPILING EXPRESSION---")

# integerConstant | stringConstant | keywordConstant | varName |
# varName '[' expression ']' | subroutineCall | '(' expression ')' | unaryOp term
def compile_term():                 # may contain array indexing[], subroutineCall, or ( expression )
    print("---COMPILING TERM---")

    if get_current_token() in ARITHMETIC_UNARY.keys():
        unary_op = get_and_advance()    # unaryOp
        compile_term()                  # term
        VMWriter.writeArithmetic(ARITHMETIC_UNARY[unary_op])
    elif get_current_token() == "(":
        advance()
        compile_expression()
        advance()
    elif get_current_type() == "integerConstant":
        VMWriter.writePush("constant", get_current_token())
        advance()
    elif get_current_type() == "stringConstant":
        compile_string()
    elif get_current_type() == "keyword":
        compile_keyword()
    else:                           # var / subroutine
        if get_next_token() == "[": # array
            array_name = get_and_advance()

            advance()
            compile_expression()
            advance()

            array_kind = SymbolTable.kindOf(array_name)
            array_index = SymbolTable.indexOf(array_name)
            VMWriter.writePush(convert_kind(array_kind), array_index)

            VMWriter.writeArithmetic("add")
            VMWriter.writePop("pointer", 1)
            VMWriter.writePush("that", 0)
        elif get_next_token() in [".", "("]:    # subroutineCall
            compile_subroutineCall()
        else:
            var_name = get_and_advance()
            var_kind = convert_kind(SymbolTable.kindOf(var_name))
            var_index = SymbolTable.indexOf(var_name)
            VMWriter.writePush(var_kind, var_index)

    print("---DONE COMPILING TERM---")

def compile_expressionList():       # (expression (, expression)*)?
    print("---COMPILING EXPRESSION LIST---")

    number_args = 0

    if get_current_token() != ")":
        number_args += 1
        compile_expression()

    while get_current_token() != ")":
        number_args += 1
        advance()                   # ,
        compile_expression()

    print("---DONE COMPILING EXPRESSION LIST---")
    return number_args

def compile_keyword():
    print("---COMPILING KEYWORD---")

    keyword = get_and_advance()

    if keyword == "this":
        VMWriter.writePush("pointer", 0)
    else:
        VMWriter.writePush("constant", 0)

        if keyword == "true":
            VMWriter.writeArithmetic("not")

# subroutineName ( expressionList ) | (className | varName) . subroutineName ( expressionList )
def compile_subroutineCall():
    print("---COMPILING SUBROUTINE CALL---")

    identifier = get_and_advance()
    function_name = identifier
    number_args = 0

    if get_current_token() == ".":                  # className (class) | varName (object)
        advance()                                   # .
        subroutine_name = get_and_advance()         # subroutine_name

        var_type = SymbolTable.typeOf(identifier)

        if var_type != "NONE":      # object_instance.subroutineCall(params)
            obj_type = SymbolTable.typeOf(identifier)
            obj_kind = convert_kind(SymbolTable.kindOf(identifier))
            obj_index = SymbolTable.indexOf(identifier)
            VMWriter.writePush(obj_kind, obj_index)      # push local 3

            function_name = obj_type + "." + subroutine_name
            number_args += 1
        else:                       # class_name.subroutineCall(params)
            class_name = identifier
            function_name = class_name + "." + subroutine_name

    elif get_current_token() == "(":                # subroutineName ( expressionList )
        subroutine_name = identifier
        class_name = get_class_name()
        function_name = class_name + "." + subroutine_name
        number_args += 1

        VMWriter.writePush("pointer", 0)            # this is a method call

    advance()       # (
    number_args += compile_expressionList()
    advance()       # )

    VMWriter.writeCall(function_name, number_args)
    print("---DONE COMPILING SUBROUTINE CALL---")

def compile_string():
    print("---COMPILING STRING---")

    string = get_and_advance()

    VMWriter.writePush("constant", len(string))
    VMWriter.writeCall("String.new", 1)

    for char in string:
        VMWriter.writePush("constant", ord(char))
        VMWriter.writeCall("String.appendChar", 2)

    print("---DONE COMPILING STRING---")

def get_and_advance():              # get current token, then increment current_token_number
    token = get_current_token()
    advance()
    return token

def advance():                      # increment current_token_number
    global tokens, current_token_number

    print(tokens[current_token_number])

    current_token_number += 1

def get_current_token():            # returns the current token to be parsed
    global tokens, current_token_number

    try:
        token = tokens[current_token_number]
    except:
        token = "FAILED_GET_CURRENT_TOKEN"

    # if token.startswith('"'):   # stringConstant
    #     return token[1:-1]

    return token

def get_next_token():
    global tokens, current_token_number

    try:
        return tokens[current_token_number + 1]
    except:
        return "FAILED_GET_NEXT_TOKEN"

def get_previous_token():
    global tokens, current_token_number

    return tokens[current_token_number - 1]

def get_current_type():             # returns the token_type of the current token to be parsed
    global tokens, current_token_number

    token = get_current_token()

    if token in keyword_list:
        return "keyword"
    elif token in symbol_list:
        return "symbol"
    elif token.isdigit():
        return "integerConstant"
    elif token.startswith('"'):
        return "stringConstant"
    else:
        return "identifier"

def get_class_name():
    global class_name

    return class_name

keyword_list = ['class', 'constructor', 'function', 'method', 'field', 'static', 'var', 'int',
                'char', 'boolean', 'void', 'true', 'false', 'null', 'this', 'let', 'do', 'if',
                'else', 'while', 'return']

symbol_list = ['{', '}', '(', ')', '[', ']', '.', ',', ';', '+', '-', '*', '/', '&', '|', '<', '>', '=', '~']

operator_list = ['+', '-', '*', '/', '&', '|', '<', '>', '=']

ARITHMETIC = {
    '+': 'add',
    '-': 'sub',
    '=': 'eq',
    '>': 'gt',
    '<': 'lt',
    '&': 'and',
    '|': 'or'
}

ARITHMETIC_UNARY = {
    '-': 'neg',
    '~': 'not'
}

def convert_kind(kind):     # converts "field" to "this"
    if kind == "field":
        return "this"

    return kind


import argparse
import inspect
import re
import time
from abc import ABCMeta, abstractclassmethod
from pathlib import Path
from contextlib import contextmanager

import pandas as pd

def get_arguments():
    parser = argparse.ArgumentParser()
    parser.add_argument("--train", type=str, default="data/1.train_data.csv")
    parser.add_argument("--test", type=str, default="data/2.test_data.csv")
    parser.add_argument("-f", "--force", action="store_true")
    return parser.parse_args()

def is_AbstructFeature(v):
    return (
        inspect.isclass(v)
        and issubclass(v, AbstructFeature)
        and not inspect.isabstract(v)
    )

def get_features(namespace: dict):
    for k, v in namespace.items():
        if is_AbstructFeature(v):
            yield v()

def generate_features(namespace: dict, isOverwrite: bool = False):
    for feature in get_features(namespace):
        if (
            not isOverwrite
            and feature.train_path.exists()
            and feature.test_path.exists()
        ):
            print(f"Generating `{feature.name}` feature was skipped.")
        else:
            feature.run().save()
            del feature

@contextmanager
def timer(name: str):
    t = time.time()
    print(f"[{name}] start")
    yield
    print(f"[{name}] is done in {time.time() - t:.0f} s")

class AbstructFeature(metaclass=ABCMeta):

    PREFIX = ""
    SUFFIX = ""
    DIR = "."

    def __init__(self):
        if self.__class__.__name__.isupper():
            self.name = self.__class__.__name__.lower()
        else:
            self.name = re.sub(
                r"([A-Z])", lambda x: f"_{x.group(1).lower()}", self.__class__.__name__
            ).lstrip("_")
        self._train = pd.DataFrame()
        self._test = pd.DataFrame()
        self.train_path = Path(self.DIR) / f"{self.name}_train.ftr"
        self.test_path = Path(self.DIR) / f"{self.name}_test.ftr"

    def run(self):
        with timer(self.name):
            self.create_features()
            prefix = f"{self.PREFIX}_" if self.PREFIX else ""
            suffix = f"_{self.SUFFIX}" if self.SUFFIX else ""
            self._train.columns = prefix + self._train.columns + suffix
            self._test.columns = prefix + self._test.columns + suffix
        return self

    @abstractclassmethod
    def create_features(self):
        raise NotImplementedError

    def save(self):
        self._train.to_feather(str(self.train_path))
        self._test.to_feather(str(self.test_path))


from ast import Not
import types
from typing import Union, Tuple, List, Iterable, Dict
import torch
from torch import nn, Tensor
from torch.nn import CrossEntropyLoss
from ...modeling import NNModule, StableDropout

class WeightedLayerPooling(nn.Module):
    """
    Token embeddings are weighted mean of their different hidden layer representations
    """
    def __init__(self, num_hidden_layers: int = 12, layer_start: int = 4, layer_weights = None):
        super(WeightedLayerPooling, self).__init__()
        self.config_keys = ['word_embedding_dimension', 'layer_start', 'num_hidden_layers']
        self.layer_start = layer_start
        self.num_hidden_layers = num_hidden_layers
        self.layer_weights = layer_weights if layer_weights is not None \
                            else nn.Parameter(torch.tensor([1] * (num_hidden_layers + 1 - layer_start), dtype=torch.float))

    def forward(self, word_embeddings):
        all_layer_embedding = torch.stack(word_embeddings)
        all_layer_embedding = all_layer_embedding[self.layer_start:, :, :, :]  # Start from 4th layers output
        weight_factor = self.layer_weights.unsqueeze(-1).unsqueeze(-1).unsqueeze(-1).expand(all_layer_embedding.size())
        weighted_average = (weight_factor * all_layer_embedding).sum(dim=0) / self.layer_weights.sum()
        return weighted_average

class XuciModel(NNModule):
    def __init__(self, model_config, mlm_model, weight_layer_pooler=False, drop_out=None):
        super().__init__()
        self.config = model_config
        if weight_layer_pooler:
            self.pooler = WeightedLayerPooling()
        else:
            self.pooler = None
        self.classifier = nn.Linear(model_config.hidden_size * 3, 2, bias=False)
        drop_out = model_config.hidden_dropout_prob if drop_out is None else drop_out
        self.dropout = StableDropout(drop_out)
        self.apply(self.init_weights)
        self.bert = mlm_model.base_model

    def forward(self, input_ids, compare_pos, position_ids=None, attention_mask=None, token_type_ids=None, labels=None):
        # input_ids_a = input_ids[:, 0, ...].squeeze()
        # input_ids_b = input_ids[:, 1, ...].squeeze()
        # attention_mask_a = attention_mask[:, 0, ...].squeeze()
        # attention_mask_b = attention_mask[:, 1, ...].squeeze()
        input_ids = input_ids.view(-1, input_ids.size(-1))
        attention_mask = attention_mask.view(-1, attention_mask.size(-1))
        outputs = self.bert(input_ids, token_type_ids=token_type_ids, attention_mask=attention_mask)
        prediction_scores = outputs['last_hidden_state']
        # sequence_output_b, _ = self.bert(input_ids_b, token_type_ids=token_type_ids, attention_mask=attention_mask_b)
        prediction_scores = prediction_scores.view(-1, 2, prediction_scores.size(1), prediction_scores.size(2))
        sequence_output_a, sequence_output_b = torch.unbind(prediction_scores, dim=1)
        # sequence_output_b = prediction_scores[:, 1, ...].squeeze()
        tokens_a = []
        tokens_b = []
        for so_a, so_b, pos in zip(sequence_output_a, sequence_output_b, compare_pos):
            a = so_a.index_select(0, pos[0][pos[0] > 0]).mean(0)
            b = so_b.index_select(0, pos[1][pos[1] > 0]).mean(0)
            tokens_a.append(a)
            tokens_b.append(b)

        tokens_a = torch.stack(tokens_a)
        tokens_b = torch.stack(tokens_b)

        # cosine similarity loss
        # cos = torch.nn.CosineSimilarity(dim=1, eps=1e-6)
        # logits = cos(tokens_a, tokens_b)
        # loss_fn = MSELoss()
        # loss = loss_fn(logits, labels.half())

        # according to SentenceBERT, use u,v,u-v as output
        scores = torch.cat([tokens_a, tokens_b, torch.abs(tokens_a - tokens_b)], -1)
        scores = self.dropout(scores)
        logits = self.classifier(scores).float()

        labels = labels.long().squeeze()

        loss_fn = CrossEntropyLoss() #
        loss = loss_fn(logits, labels)

        return {
                'logits' : logits,
                'loss' : loss,
                'labels': labels
            }


import sys
input = sys.stdin.readline
# 그냥 단순히 3중 for문으로 돌리게 되면 시간 초과 발생
def tri(lengths):
    lengths = sorted(lengths)
    a, b, c = lengths[0], lengths[1], lengths[2] # min -> max
    if c < a+b:
        return True
    return False

if __name__ == "__main__":
    n = int(input())
    answer = -1
    data = []
    for _ in range(n):
        data.append(int(input()))
    data = sorted(data, reverse = True)

    # 역순으로 우선 정렬을 해 준 뒤에 삼각형의 결정조건을 이용하기 위해
    while len(data) >= 3:
        # 현재 리스트에서 제일 긴 3개의 길이
        # 만약에 a가 b+c보다 길다면 나머지 경우는 당연히 삼각형이 만들어지지 않기 때문에
        # 이상황에서 break를 해야 한다.
        a, b, c = data[0], data[1], data[2]
        if tri([a, b, c]) == False:
            data.pop(0)
        else:
            answer = a+b+c
            break

    print(answer)


import fnmatch
from setuptools import find_packages, setup
from setuptools.command.build_py import build_py as build_py_orig

with open("README.rst", "r") as fh:
    long_description = fh.read()

setup(
    name="Grimsel",
    version="0.0.12",
    author="Grimsel contributors listed in AUTHORS",
    author_email="mcsoini_dev@posteo.org",
    description=("GeneRal Integrated Modeling environment for the Supply of"
                 " Electricity and Low-temperature heat"),
    long_description=long_description,
    long_description_content_type="text/x-rst",
    url="https://github.com/mcsoini/grimsel",
    packages=find_packages(),
    install_requires=['pyutilib>=5.8.0',
                      'pandas>=1.0.0',
                      'pyomo==5.6.9',
                      'wrapt>=1.12.1',
                      'psycopg2>=2.8.5',
                      'numpy>=1.18.2',
                      'sqlalchemy>=1.3.16',
                      'statsmodels>=0.11.1',
                      'tables>=3.6.1',
                      'fastparquet>=0.3.3',
                      'matplotlib>=3.2.1',
                      'tabulate>=0.8.7'
                      ],
     classifiers=[
        "Programming Language :: Python :: 3.8",
        "Operating System :: OS Independent"],
)


#N,M,K 입력 받기
N,M,K = map(int,input().split())
#배열 입력 받기
ary = list(map(int,input().split()))

result = 0

ary.sort()

Max = input[:-1]
Second = input[:-2]

#M은 최종 연산 하는 횟수
while True:
    #최대값을 k번 더해주는 연산 실시
    for i in range(k):
        if M == 0:
            break
        result += Max
        m -= 1 #같은 수를 저장하는 데는 횟수 제한이 있다.

    if M == 0:
        break

    result += Second
    M -= 1

print(result)


import json
import os
from microprediction.live.xraytickers import XRAY_TICKERS_JSON
from microprediction.whereami import TOP
from getjson import getjson

XRAY_TICKERS_OLD_JSON = os.path.join(TOP,'live', 'xraytickers_old.json')
XRAY_TICKERS_DISCARDED_JSON = os.path.join(TOP,'live', 'xraytickers_discarded.json')

def get_xray_tickers_discarded() -> [str]:
    """ Retrieve discarded xray tickers """
    url = 'https://raw.githubusercontent.com/microprediction/microprediction/master/microprediction/live/xraytickers_discarded.json'
    data = getjson(url, failover_url=url)
    return [data[str(i)] for i in range(len(data))]

if __name__=='__main__':

    with open(XRAY_TICKERS_OLD_JSON) as fh:
        old_tickers = json.load(fh)

    with open(XRAY_TICKERS_JSON) as fh:
        new_tickers = json.load(fh)

    discarded = [(k, v) for (k,v) in old_tickers.items() if k not in new_tickers]

    with open(XRAY_TICKERS_DISCARDED_JSON, 'wt') as fp:
        json.dump(obj=discarded, fp=fp)


__author__ = 'zsx'

import numpy as np
import copy
from utils.table import contingency_table_multicategory

def single_hss(truths, predictions, classes=None, threshold=None):
    """Determines the Heidke Skill Score, returning a scalar. See
    `here <http://www.cawcr.gov.au/projects/verification/#Methods_for_multi-category_forecasts>`_
    for more details on the Peirce Skill Score
    :param truths: The true labels of these data
    :param predictions: The predictions of the model
    :param classes: an ordered set for the label possibilities. If not given,
        will be deduced from the truth values
    :param threshold: for radar classify
    :returns: a single value for the heidke skill score
    """
    table = _get_contingency_table(truths, predictions, classes, threshold)
    return _peirce_skill_score(table)

def _get_contingency_table(truths, predictions, classes=None, threshold=None):
    """Uses the truths and predictions to compute a contingency matrix
    :param truths: The true labels of these data
    :param predictions: The predictions of the model
    :param classes: an ordered set for the label possibilities. If not given,
        will be deduced from the truth values if possible
    :returns: a numpy array of shape (num_classes, num_classes)
    """
    if len(truths) != len(predictions):
        raise ValueError("The shape of predictions and truths are not the same!")
    # Truths and predictions are now both deterministic
    if classes is None:
        classes = np.unique(np.append(np.unique(truths), np.unique(predictions)))
        preds = predictions
        labels = truths
    else:
        preds = _radar_classify(predictions, threshold)
        labels = _radar_classify(truths, threshold)
    """
    table =[]
    for i, c1 in enumerate(classes):
        c = Counter(preds[np.where(labels == c1)])
        single_row = []
        for j in range(len(classes)):
            single_row.append(c[j])
        table.append(single_row)
    table = np.array(table).astype(np.float32)
    """

    table = np.zeros((len(classes), len(classes)), dtype=np.float32)
    for i, c1 in enumerate(classes):
        for j, c2 in enumerate(classes):
            for p, t in zip(preds, labels):
                table[i, j] += [p1 == c1 and t1 == c2 for p1, t1 in zip(p, t)].count(True)

    return table

def _radar_classify(inputs, threshold=None):
    # classify into 5 classes
    # threshold = [0, 20, 30, 40, 50, 70]
    if threshold is None:
        threshold = [0, 20, 30, 40, 50, 70]
    inputs_logit = copy.deepcopy(inputs)
    inputs_logit[inputs_logit <= threshold[1]] = 1
    for i in range(1, len(threshold) - 1):
        inputs_logit[(threshold[i] < inputs) & (inputs <= threshold[i + 1])] = i + 1
    return inputs_logit

def _peirce_skill_score(table):
    """This function is borrowed with modification from the hagelslag repository
    MulticlassContingencyTable class. It is used here with permission of
    David John Gagne II <djgagne@ou.edu>
    Multiclass Peirce Skill Score (also Hanssen and Kuipers score, True Skill Score)
    """
    n = float(table.sum())
    nf = table.sum(axis=1)
    no = table.sum(axis=0)
    correct = float(table.trace())
    no_squared = (no * no).sum()
    if n ** 2 == no_squared:
        return correct / n
    else:
        return (n * correct - (nf * no).sum()) / (n ** 2 - no_squared)

def batch_hss(truths, predictions, classes=None, threshold=None):
    # truths's shape: [batch, width, height]
    # batch_hss calculate the same time step
    bat_num = truths.shape[0]
    bat_hss = 0
    for i in range(bat_num):
        hss = single_hss(truths[i], predictions[i], classes, threshold)
        bat_hss += hss
    return bat_hss

def prep_clf(obs, pre, threshold=0.5):
    """
    func: 计算二分类结果-混淆矩阵的四个元素
    inputs:
        obs: 观测值，即真实值；
        pre: 预测值；
        threshold: 阈值，判别正负样本的阈值,默认0.1,气象上默认格点 >= 0.1才判定存在降水。

    returns:
        hits, misses, falsealarms, correctnegatives
        #aliases: TP, FN, FP, TN
    """
    # 根据阈值分类为 0, 1
    obs = np.where(obs >= threshold, 1, 0)
    pre = np.where(pre >= threshold, 1, 0)

    # True positive (TP)
    hits = np.sum((obs == 1) & (pre == 1))

    # False negative (FN)
    misses = np.sum((obs == 1) & (pre == 0))

    # False positive (FP)
    falsealarms = np.sum((obs == 0) & (pre == 1))

    # True negative (TN)
    correctnegatives = np.sum((obs == 0) & (pre == 0))

    return hits, misses, falsealarms, correctnegatives

def HSS(obs, pre, threshold=0.5):
    """
    HSS - Heidke skill score
    Args:
        obs (numpy.ndarray): observations
        pre (numpy.ndarray): pre
        threshold (float)  : threshold for rainfall values binaryzation
                             (rain/no rain)
    Returns:
        float: HSS value
    """
    hits, misses, falsealarms, correctnegatives = prep_clf(obs=obs, pre=pre, threshold=threshold)

    HSS_num = 2 * (hits * correctnegatives - misses * falsealarms)
    HSS_den = (misses ** 2 + falsealarms ** 2 + 2 * hits * correctnegatives +
               (misses + falsealarms) * (hits + correctnegatives))

    return HSS_num / HSS_den

# github: github.com/nmcdev/meteva/blob/7524be059bdbae58fe46a7bf37b306b6fef0b5b3/meteva/method/multi_category/score.py
# usage document: https://www.showdoc.cc/meteva?page_id=3975612394328262
def meteva_tc(ob, fo, grade_list=None):
    """
    accuracy 求多分类预报准确率
    :param ob: 实况数据 不确定维numpy
    :param fo:  预测数据 不确定维numpy
    :param grade_list:等级，如果grade_list= None则ob和fo里的值代表类别，否则，根据grade_list来进行分类
    :return: 返回一维数组，包括（总样本数，正确数）
    """
    # 多分类预报准确率
    if grade_list is None:
        # ob 和fo是不确定维的numpy数组，其中每个值是代表分类的类别
        ob1 = ob.reshape((-1))
        fo1 = fo.reshape((-1))
    else:
        ob1 = np.zeros_like(ob)
        fo1 = np.zeros_like(fo)
        # ob 和fo 是连续的变量，通过 threshold_list 将ob 和fo划分成连续的等级之后再计算等级准确性
        for index in range(len(grade_list) - 1):
            ob_index_list = np.where((grade_list[index] <= ob) & (ob < grade_list[index + 1]))
            ob1[ob_index_list] = index + 1
            fo_index_list = np.where((grade_list[index] <= fo) & (fo < grade_list[index + 1]))
            fo1[fo_index_list] = index + 1
        ob_index_list = np.where(grade_list[-1] <= ob)
        ob1[ob_index_list] = len(grade_list)
        fo_index_list = np.where(grade_list[-1] <= fo)
        fo1[fo_index_list] = len(grade_list)
    correct_num = np.sum(fo1 == ob1)
    return np.array([ob.size, correct_num])

def meteva_accuracy(ob, fo, grade_list=None):
    """
    accuracy 求多分类预报准确率
    :param ob: 实况数据 任意维numpy数组
    :param fo: 预测数据 任意维numpy数组,Fo.shape 和Ob.shape一致
    :param grade_list: 如果该参数为None，观测或预报值出现过的值都作为分类标记.
    如果该参数不为None，它必须是一个从小到大排列的实数，以其中列出的数值划分出的多个区间作为分类标签。
    对于预报和观测值不为整数的情况，grade_list 不能设置为None。
    :return: 0-1的实数，0代表无技巧，最优预报为1
    """
    tc1 = meteva_tc(ob, fo, grade_list)
    total_count = tc1[0]
    correct_count = tc1[1]
    accuracy_score = correct_count / total_count
    return accuracy_score

def meteva_hss(ob, fo, grade_list=None):
    """
    hss heidke技能得分,它表现实际的预报的分类准确性相对于随机分类达到的准确性的技巧
    :param ob: 实况数据 任意维numpy数组
    :param fo: 预测数据 任意维numpy数组,Fo.shape 和Ob.shape一致
    :param grade_list: 如果该参数为None，观测或预报值出现过的值都作为分类标记.
    如果该参数不为None，它必须是一个从小到大排列的实数，以其中列出的数值划分出的多个区间作为分类标签。
    对于预报和观测值不为整数的情况，grade_list 不能设置为None。
    :return:
    """
    IV = 999999
    conf_mx = contingency_table_multicategory(ob, fo, grade_list)
    accuracy_score = meteva_accuracy(ob, fo, grade_list)
    total_num = ob.size
    NF_array = conf_mx[0:-1, -1]
    NO_array = conf_mx[-1, 0:-1]
    random_score = np.dot(NF_array, NO_array) / (total_num * total_num)
    if random_score == 1:
        HSS = IV  # IV
    else:
        HSS = (accuracy_score - random_score) / (1 - random_score)
    return HSS


"""Implements helpers for training."""

import copy
import numpy as np
import torch

from torch.utils.data import DataLoader, ConcatDataset
from permutation_sharing.model.struct_fc_model import StructFCModel
from permutation_sharing.model.deep_set_model import DeepSetModel
from struct_discovery.solver.hypergrad import implicit_function

from struct_discovery.evaluation.partition_distance import partition_distance

def get_dataloader(input_dataset, batch_size=128, shuffle=True, drop_last=True):
    input_dataloader = DataLoader(input_dataset, batch_size=batch_size,
                                  shuffle=shuffle, drop_last=drop_last)
    return input_dataloader

def create_loader(method, datasets):
    train_dataset, val_dataset, hyper_dataset = datasets
    if method in ['oracle', 'deep_set', 'no_share']:
        # Oracle doesn't search for A, directly use all data
        train_val_dataset = ConcatDataset([train_dataset, val_dataset])
        train_loader = get_dataloader(train_val_dataset, batch_size=len(
            train_val_dataset), shuffle=True, drop_last=True)
        val_loader = None
    else:
        train_loader = get_dataloader(train_dataset, batch_size=len(
            train_dataset), shuffle=True, drop_last=True)
        val_loader = get_dataloader(val_dataset, batch_size=len(
            val_dataset), shuffle=True, drop_last=True)
    # hyper_dataset is for all other hyperparameters (learning stopping, learning rate, etc.)
    hyper_loader = get_dataloader(hyper_dataset, batch_size=len(
        hyper_dataset), shuffle=False, drop_last=False)
    return train_loader, val_loader, hyper_loader

def get_data_mean_std(datasets):
    train_dataset, val_dataset, _ = datasets
    train_label = train_dataset.label
    val_label = val_dataset.label
    data_label = np.concatenate([train_label, val_label], 0)
    return data_label.mean(), data_label.std()

def fit_one_model(method, datasets):
    train_loader, val_loader, hyper_loader = create_loader(method, datasets)
    # Compute mean and std from data.
    data_mean, data_std = get_data_mean_std(datasets)
    hyper_params = {'lr': 1e-3, 'num_epoch': 100000,
                    'patience': 1000, 'data_mean': data_mean, 'data_std': data_std}
    if method == 'oracle':
        model = fit_oracle(train_loader, val_loader,
                           hyper_loader, hyper_params)

    if method == 'deep_set':
        model = fit_deep_set(train_loader, val_loader,
                             hyper_loader, hyper_params)

    elif method == 'no_share':
        model = fit_no_share(train_loader, val_loader,
                             hyper_loader, hyper_params)

    elif method == 'ours':
        hyper_params['num_epoch'] = 500
        hyper_params['lr'] = 1e-3
        hyper_params['outer_lr'] = 1e-2
        hyper_params['num_inner'] = 250
        hyper_params['patience'] = 100
        val_loss_best = np.inf
        if train_loader.dataset.A_rank == 1:
            # Non-convex optimization try random initialization.
            init_modes = ['uniform', 'uniform1', 'uniform2']
        else:
            init_modes = ['uniform', 'uniform1', 'uniform2']

        for init_mode in init_modes:
            A_best, _ = fit_ours_double_loop(
                train_loader, val_loader, hyper_loader, hyper_params, init_mode)
            torch.manual_seed(1)
            model = StructFCModel(max_length=hyper_loader.dataset.max_length,
                                  A_init=A_best,
                                  data_mean=hyper_params['data_mean'],
                                  data_std=hyper_params['data_std'])
            hyper_fit_params = {'lr': 1e-3,
                                'num_epoch': 100000, 'patience': 1000}
            model = fit_standard_model(
                train_loader, val_loader, model, hyper_fit_params)
            val_loss = eval_model(model, val_loader)
            # Check on val to prevent underfitting of A.
            if val_loss_best > val_loss:
                val_loss_best = val_loss
                A_best_best = A_best

        # Finally, retrain on all the data.
        torch.manual_seed(2)
        model = StructFCModel(max_length=hyper_loader.dataset.max_length,
                              A_init=A_best_best,
                              data_mean=hyper_params['data_mean'],
                              data_std=hyper_params['data_std'])
        train_val_dataset = ConcatDataset(
            [train_loader.dataset, val_loader.dataset])
        train_val_loader = get_dataloader(train_val_dataset, batch_size=len(
            train_val_dataset), shuffle=True, drop_last=True)
        hyper_fit_params = {'lr': 1e-3, 'num_epoch': 100000, 'patience': 1000}
        model = fit_standard_model(
            train_val_loader, hyper_loader, model, hyper_fit_params)
    return model

def fit_oracle(train_loader, val_loader, hyper_loader, hyper_params):
    assert val_loader is None
    torch.manual_seed(0)
    model = StructFCModel(max_length=hyper_loader.dataset.max_length, A_init=hyper_loader.dataset.A,
                          data_mean=hyper_params['data_mean'],
                          data_std=hyper_params['data_std'])
    best_model = fit_standard_model(
        train_loader, hyper_loader, model, hyper_params)
    return best_model

def fit_deep_set(train_loader, val_loader, hyper_loader, hyper_params):
    assert val_loader is None
    A = np.zeros_like(hyper_loader.dataset.A)
    A[0, :] = 1.
    torch.manual_seed(0)
    model = StructFCModel(max_length=hyper_loader.dataset.max_length, A_init=A,
                          data_mean=hyper_params['data_mean'],
                          data_std=hyper_params['data_std'])
    best_model = fit_standard_model(
        train_loader, hyper_loader, model, hyper_params)
    return best_model

def fit_no_share(train_loader, val_loader, hyper_loader, hyper_params):
    assert val_loader is None
    torch.manual_seed(0)
    model = StructFCModel(max_length=hyper_loader.dataset.max_length,
                          A_init=np.eye(hyper_loader.dataset.max_length),
                          data_mean=hyper_params['data_mean'],
                          data_std=hyper_params['data_std'])
    best_model = fit_standard_model(
        train_loader, hyper_loader, model, hyper_params)
    return best_model

def fit_ours_double_loop(train_loader, val_loader, hyper_loader, hyper_params, init_mode):
    inner_lr = hyper_params['lr']
    outer_lr = hyper_params['outer_lr']
    num_epoch = hyper_params['num_epoch']
    num_inner = hyper_params['num_inner']
    patience = hyper_params['patience']
    warmup = 30
    max_len = hyper_loader.dataset.max_length
    torch.manual_seed(0)
    model = StructFCModel(max_length=max_len,
                          data_mean=hyper_params['data_mean'],
                          data_std=hyper_params['data_std'])

    model.cuda()
    if init_mode == 'uniform2':
        with torch.no_grad():
            torch.nn.init.uniform_(model.structure, -0.1, 0.1)
    if init_mode == 'uniform1':
        with torch.no_grad():
            model.structure.data *= -1

    model_optimizer = torch.optim.AdamW(
        model.model_parameters(), inner_lr, weight_decay=1e-3)
    hyper_optimizer = torch.optim.Adam(model.hyper_parameters(), outer_lr)
    hyper_scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(
        hyper_optimizer, 'min', factor=0.5, patience=50, cooldown=0)

    epoch_count = 0
    x_hyper, y_hyper = hyper_loader.dataset.data, hyper_loader.dataset.label
    x_val, y_val = val_loader.dataset.data, val_loader.dataset.label
    x, y = train_loader.dataset.data, train_loader.dataset.label

    x_hyper, y_hyper = torch.from_numpy(
        x_hyper).cuda(), torch.from_numpy(y_hyper).cuda()
    x_val, y_val = torch.from_numpy(
        x_val).cuda(), torch.from_numpy(y_val).cuda()
    x, y = torch.from_numpy(x).cuda(), torch.from_numpy(y).cuda()

    best_val_loss = np.inf
    for k in range(num_epoch):
        # Inner loop.
        for _ in range(num_inner):
            y_pred = model.forward(x)
            inner_loss = model.total_loss(y_pred, y)
            model.zero_grad()
            inner_loss.backward()
            model_optimizer.step()

        # Outer loop.
        # Computes hypergradient.
        hyper_grad = implicit_function.compute_hypergrad(
            (x, y),
            (x_val, y_val),
            model,
            hyper_optimizer,
            method='NEUMANN')
        model.zero_grad()
        # Update hypergradient.
        with torch.no_grad():
            bidx = 0
            for mm in model.hyper_parameters():
                mm_size = mm.nelement()
                eidx = bidx + mm_size
                mm.grad = torch.reshape(
                    hyper_grad[bidx:eidx, :], mm.shape).clone()
        torch.nn.utils.clip_grad_norm_(model.hyper_parameters(), 25)
        hyper_optimizer.step()
        if patience == 0:
            break
        patience -= 1
        # Early stopping check on hyper set.
        with torch.no_grad():
            y_pred = model.forward(x_val)
            outer_loss = model.total_val_loss(y_pred, y_val).item()

        if k >= warmup:
            hyper_scheduler.step(outer_loss)

        if best_val_loss > outer_loss*1.0001 and k >= warmup:  # Warmup
            print('Epoch: %s' % k)
            print(outer_loss)
            print(model.forward_A().argmax(1))
            best_val_loss = outer_loss
            best_model = copy.deepcopy(model)
            # reset patience
            patience = hyper_params['patience']

    # Get A_val
    A_best_idx = best_model.forward_A().data.cpu().numpy().argmax(-1)
    A_best = np.zeros((max_len, max_len))
    A_best[np.arange(0, max_len), A_best_idx] = 1
    return A_best, best_val_loss

def fit_standard_model(train_loader, hyper_loader, model, hyper_params):
    torch.manual_seed(0)
    model.cuda()
    # Optimizer.
    lr = hyper_params['lr']
    num_epoch = hyper_params['num_epoch']
    patience = hyper_params['patience']
    model_optimizer = torch.optim.Adam(model.model_parameters(), lr,)
    model_scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(
        model_optimizer, 'min', factor=0.25, patience=1000)

    best_hyper_loss = np.inf
    best_model = None
    for epoch in range(num_epoch):
        for x, y in train_loader:
            x = x.cuda()
            y = y.cuda()
            y_hat = model(x)
            model.zero_grad()
            train_loss = model.total_loss(y_hat, y)
            train_loss.backward()
            model_optimizer.step()
        model_scheduler.step(train_loss)
        # Evaluation + logging here.
        hyper_loss = eval_model(model, hyper_loader)
        if patience == 0:
            break
        patience -= 1
        if best_hyper_loss > hyper_loss*1.0001:
            # Save the best model.
            best_hyper_loss = hyper_loss
            best_model = copy.deepcopy(model)
            patience = hyper_params['patience']
    return best_model

def eval_model(model, data_loader, is_test=False):
    total_loss = 0
    total_mae_loss = 0
    total_mse_loss = 0
    total_acc = 0
    total_pd = 0
    count = 0
    with torch.no_grad():
        for x, y in data_loader:
            x = x.cuda()
            y = y.cuda()
            if is_test:
                y_hat = model.predict(x)
            else:
                y_hat = model(x)
            loss = model.total_loss(y_hat, y).item()
            total_loss += loss*y_hat.shape[0]
            count += y.shape[0]
            if is_test:
                total_mae_loss += torch.sum(torch.abs(y_hat.squeeze() -
                                                      y.squeeze())).item()
                total_mse_loss += torch.sum((y_hat.squeeze() -
                                             y.squeeze())**2).item()
                total_acc += torch.sum(torch.round(y_hat)
                                       == y.int()).float().item()
    if is_test:
        total_mae_loss = total_mae_loss/count
        total_mse_loss = total_mse_loss/count
        total_acc = total_acc/count
        A_best_idx = model.forward_A().data.cpu().numpy().argmax(-1)
        A_best = np.zeros_like(data_loader.dataset.A)
        A_best[np.arange(0, A_best.shape[0]), A_best_idx] = 1
        total_pd = partition_distance(A_best, data_loader.dataset.A)
        return total_mae_loss, total_mse_loss, total_acc, total_pd
    else:
        return total_loss/count