Análise de dados e modelo básico
Introdução
Este artigo é baseado em dados de uma competição que a Driven Data publicou para abordar problemas de fontes de água na Tanzânia.
As informações para a competição foram obtidas pelo Ministério de Recursos Hídricos da Tanzânia usando uma plataforma de código aberto chamada Taarifa. A Tanzânia é o maior país da África Oriental, com uma população de cerca de 60 milhões. Metade da população não tem acesso a água potável e 2/3 da população sofre de saneamento deficiente. Em lares pobres, as famílias muitas vezes precisam passar horas a pé para obter água das bombas d'água.
Bilhões de dólares em ajuda externa estão sendo fornecidos para lidar com o problema de água doce da Tanzânia. No entanto, o governo da Tanzânia não foi capaz de resolver esse problema até hoje. Uma parte significativa das bombas de água está completamente avariada ou praticamente não funciona, e as restantes requerem grandes reparações. O Ministério dos Recursos Hídricos da Tanzânia concordou com a Taarifa e lançou um concurso na esperança de obter dicas da comunidade sobre como realizar suas tarefas.
Dados
Existem muitas características (recursos) associadas às bombas de água nos dados, há informações relacionadas às localizações geográficas dos pontos com água, as organizações que os construíram e administram, bem como alguns dados sobre as regiões, territórios de governo locais. Também há informações sobre os tipos e número de pagamentos.
Os pontos de abastecimento de água são divididos em úteis , não funcionais e reparáveis, mas precisam de reparos . O objetivo do concurso é construir um modelo que preveja a funcionalidade dos pontos de abastecimento de água.
Os dados contêm 59.400 linhas e 40 colunas. O rótulo de destino está contido em um arquivo separado.
A métrica usada para esta competição é a taxa de classificação , que calcula a porcentagem de linhas em que a classe prevista corresponde à classe real no conjunto de teste. O valor máximo é 1 e o mínimo é 0. O objetivo é maximizar a taxa de classificação .
Análise de dados
Descrições de campos na tabela de dados:
amount_tsh - queda estática total (quantidade de água disponível para o ponto de abastecimento de água)
date_recorded —
funder —
gps_height —
installer —
longitude — GPS ()
latitude — GPS ()
wpt_name — ,
num_private —
basin —
subvillage —
region —
region_code — ()
district_code — ()
lga —
ward —
population —
public_meeting — /
recorded_by —
scheme_management —
scheme_name —
permit —
construction_year —
extraction_type —
extraction_type_group —
extraction_type_class —
management —
management_group —
payment —
payment_type —
water_quality —
quality_group —
quantity —
quantity_group —
source —
source_type —
source_class —
waterpoint_type —
waterpoint_type_group —
, — :
, . :
(under-sampling)
, (over-sampling)
— (SMOTE)
,
, .
.
, scheme_name, , .
/ . permit, installer funder.
.
, . , (quantity_group).
, , . . , . , , , .
? , quality_group.
, , . .
quality_group .
— (waterpoint_type_group).
, other . ? , .
— , , , 80- .
. , . , 500 .
Danida — , , . RWSSP ( ), Dhv . , , , . , , , . , , .
, , , . , .
— . .
, . , .
— .
, , , , - .
0 . , amount_tsh (label = 0). amount_tsh. , 500 .
, .
installer , . . .
, 71 (0,95 ), «other».
funder. — 98.
. . , . : scheme_management, quantity_group, water_quality, payment_type, extraction_type, waterpoint_type_group, region_code.
latitude longitude region_code.
subvillage scheme_name.
public_meeting permit .
subvillage, public_meeting, scheme_name, permit, , . , , .
scheme_management, quantity_group, water_quality, region_code, payment_type, extraction_type, waterpoint_type_group, date_recorded, recorded_by , , .
. , , CatBoost. .
, . .
def fit_model(train_pool, test_pool, **kwargs):
model = CatBoostClassifier(
max_ctr_complexity=5,
task_type='CPU',
iterations=10000,
eval_metric='AUC',
od_type='Iter',
od_wait=500,
**kwargs
)return model.fit(
train_pool,
eval_set=test_pool,
verbose=1000,
plot=False,
use_best_model=True)
AUC, , .
. —
def classification_rate(y, y_pred):
return np.sum(y==y_pred)/len(y)
, — . OOF (Out-of-Fold). ; . , .
def get_oof(n_folds, x_train, y, x_test, cat_features, seeds): ntrain = x_train.shape[0]
ntest = x_test.shape[0]
oof_train = np.zeros((len(seeds), ntrain, 3))
oof_test = np.zeros((ntest, 3))
oof_test_skf = np.empty((len(seeds), n_folds, ntest, 3)) test_pool = Pool(data=x_test, cat_features=cat_features)
models = {} for iseed, seed in enumerate(seeds):
kf = StratifiedKFold(
n_splits=n_folds,
shuffle=True,
random_state=seed)
for i, (train_index, test_index) in enumerate(kf.split(x_train, y)):
print(f'\nSeed {seed}, Fold {i}')
x_tr = x_train.iloc[train_index, :]
y_tr = y[train_index]
x_te = x_train.iloc[test_index, :]
y_te = y[test_index]
train_pool = Pool(data=x_tr, label=y_tr, cat_features=cat_features)
valid_pool = Pool(data=x_te, label=y_te, cat_features=cat_features)model = fit_model(
train_pool, valid_pool,
loss_function='MultiClass',
random_seed=seed
)
oof_train[iseed, test_index, :] = model.predict_proba(x_te)
oof_test_skf[iseed, i, :, :] = model.predict_proba(x_test)
models[(seed, i)] = modeloof_test[:, :] = oof_test_skf.mean(axis=1).mean(axis=0)
oof_train = oof_train.mean(axis=0)
return oof_train, oof_test, models
, — seeds.
, .
, ().
:
balanced accuracy: 0.6703822994494413
classification rate: 0.8198316498316498
.
, -5 0,005 , , .
, — . , , .
balanced accuracy: 0.6549535670689709
classification rate: 0.8108249158249158
.
:
;
;
CatBoost, ;
OOF-;
.
A abordagem certa para preparar dados e escolher as ferramentas certas para criar um modelo pode dar excelentes resultados, mesmo sem geração de recursos adicionais.
Como tarefa de casa, sugiro adicionar novos recursos, escolher os parâmetros de modelo ideais, usar outras bibliotecas para aumentar o gradiente e construir conjuntos a partir dos modelos resultantes.
O código do artigo pode ser visto aqui .