Another approach to detecting fraud in unlabeled data is to let an algorithm identify fraud by flagging the smallest clusters based on their size. In this post, we will learn how to do this by implementing the Density-Based Spatial Clustering of Applications with Noise (DBSCAN) algorithm.
The code below provides the libraries that we will employ
from sklearn.cluster import DBSCAN
import pandas as pd
import numpy as np
from sklearn.metrics import homogeneity_score, silhouette_score
from sklearn.preprocessing import MinMaxScaler
df = pd.read_csv("C:/Users/dthom/Documents/python/fraud/chapter_3/chapter_3/banksim_adj.csv")
The main benefit of DBSCAN is that it is not necessary to specify the number of clusters we want before conducting the analysis. Using math, the algorithm clusters the data based on how far or close data points are to each other.
In addition to DBSCAN, we also need pandas and numpy to clean the data, along with MinMaxScaler to scale the data. We will also use homegeneity_score and silhouette_score to assess the clusters that are produced.
Data Preparation
In the code below, we separate the independent and dependent variables. The X object consists of columns 2 and 3, and then 5 through 20. Column 4 contains the ground truth of whether or not an example is fraudulent. We are pretending we do not have this information. The y object indicates if the example is fraudulent.
# Import the scaler
X = df.iloc[:, [1, 2] + list(range(4, 19))]
y = df.iloc[:, 3]
# Take the float values of df for X
X = df.values.astype(float)
#We know the truth but we are pretending we don't
Now we will scale our data, as this is critical when dealing with clustering techniques.
# Define the scaler and apply to the data
scaler = MinMaxScaler()
X_scaled = scaler.fit_transform(X)
We will now turn to cluster development
Cluster Development
We will now use the DBSCAN function to create our clusters. We set the epsilon to 0.9 and the minimum sample per cluster to 10. Next, we obtain the predicted labels and the number of clusters.
# Initialize and fit the DBSCAN model
db = DBSCAN(eps=.9, min_samples=10, n_jobs=-1).fit(X_scaled) #small clusters = potential outliers
# Obtain the predicted labels and calculate number of clusters
pred_labels = db.labels_
n_clusters = len(set(pred_labels)) - (1 if -1 in pred_labels else 0)
With this information, we are now ready to assess our model
Model Assessment
We will display three pieces of information here. First, the number of clusters is suggested. Next is the homogeneity, which measures the purity of a cluster in terms of only having examples that belong to the same cluster, and ranges from 0 to 1. The silhouette coefficient measures how well examples are matched to their clusters and ranges from -1 to 1.
# Print performance metrics for DBSCAN
print('Estimated number of clusters: %d' % n_clusters)
print("Homogeneity: %0.3f" % homogeneity_score(y, pred_labels))
print("Silhouette Coefficient: %0.3f" % silhouette_score(X_scaled, pred_labels))
Estimated number of clusters: 25
Homogeneity: 0.922
Silhouette Coefficient: 0.564
The values above indicate a reasonable value for the given context, but this would need to be compared to the performance of other models. Below is a breakdown of the number of examples in each of the 25 clusters.
# Count observations in each cluster number
counts = np.bincount(pred_labels[pred_labels>=0])
print(counts)
[3252 105 2714 46 174 119 112 79 52 74 43 24 45 42
11 19 16 13 10 15 35 10 40 19 11]
In the code below, we are now pulling the three smallest clusters based on sample size. The small size of these clusters shows they may be outlier examples.
# Sort the sample counts of the clusters and take the top 3 smallest clusters
smallest_clusters = np.argsort(counts)[:3]
print(smallest_clusters)
# Print the counts of the smallest clusters only
print("Their counts are:")
print(counts[smallest_clusters]) #small clusters = potential fraud
[21 18 24]
Their counts are:
[10 10 11]
The three smallest clusters have 10, 10, and 11 samples in each.
Confusion Matrix
The next step is unique because we have the true values of fraud. We will compare the three clusters we have identified as fraudulent to the ground truth values we have. In the code below, we map our cluster results to the dataframe and make a new column called predicted_fraud, which includes the three clusters with 10 or 11 examples. We then make a crosstab of these results.
# Create a dataframe of the predicted cluster numbers and fraud labels
df = pd.DataFrame({'clusternr':pred_labels,'fraud':y}) # true values are y
# Create a condition flagging fraud for the smallest clusters
df['predicted_fraud'] = np.where((df['clusternr']==10) | (df['clusternr']==11), 1, 0)
# Run a crosstab on the results
print(pd.crosstab(df['fraud'], df['predicted_fraud'], rownames=['Actual Fraud'], colnames=['Flagged Fraud']))
Flagged Fraud 0 1
Actual Fraud
0 6922 67
1 200 0
The results are actually disastrous. Our accuracy is zero percent with a huge number of false positives and negatives. To rectify this, we would have to use other clusters as our instances of fraud or consider another approach besides DBSCAN.
Conclusion
The analysis did not turn out as we had hoped, but what we did learn is the process for using the DBSCAN algorithm to handle unlabeled data. For exploratory purposes, this algorithm is powerful in initiating the process of identifying fraudulent examples.




















































