ML – Python (VII) – Overfitting & Underfitting

On the previous article, we named overfitting and underfitting but we did not go deep into details about them. Let’s just take a deeper dive on them.

When we work with a set of data to predict or classify a problem we try to achieve our goals implementing a model using the training data and testing it with the testing data. We can make adjustments based on the characteristics we are using or the model itself.

Modifying the model we can end up with a too simple model or a too complex model. Here is when we need to consider the overfitting and underfitting concepts.

Underfitting

As we can see on the image, the underfitting concept refers to a model that can neither model the training data nor generalize to new data. An underfit machine learning model is not a suitable model and will be obvious as it will have poor performance on the training data.

It happens when we do not have enough data to build a precise model or when we try to build a linear model with non-linear data.

There are a few techniques we can try to prevent underfitting:

  • Sometimes the model is underfitting because the feature items are insufficient. In this case, we can add other feature items to unfold it well.
  • Add polynomial features, which are usually utilized as a part of the machine learning algorithm. For example, the linear model is more generalized by adding quadratic or cubic terms.
  • Reduce the regularization parameters. The motivation behind regularization is to prevent overfitting, yet now the model has an underfitting, we have to diminish the regularization parameters.

Overfitting

On the opposite side, the overfitting concept refers to a model that models the training data too well. Overfitting happens when a model learns the detail and noise in the training data to the extent that it negatively impacts the performance of the model on new data.

Overfitting is more probable in non-parametric and non-linear models.

There are a few techniques we can try to prevent overfitting:

  • Cross-validation: It uses our initial training data to generate multiple mini train-test splits, and it uses these splits to tune our model. Cross-validation allows us to tune hyperparameters with only our original training set. This allows us to keep our test set as a truly unseen dataset for selecting our final model.
  • Train with more data: Training with more data can help algorithms detect the signal better but, if we just add more noisy data, this technique won’t help. That’s why we should always ensure our data is clean and relevant.
  • Remove features: We can manually improve algorithms generalizability by removing irrelevant input features. The criteria to remove them, if anything does not make sense, or if it is hard to justify, this is a good candidate to be removed.
  • Early stopping: When training an algorithm, we can measure how well each iteration of the model performs. Up until a certain number of iterations, new iterations improve the model. After that point, the model’s ability to generalize can weaken as it begins to overfit the training data. Early stopping refers to stopping the training process before the learner passes that point.
  • Regularization: Regularization refers to a broad range of techniques for artificially forcing our model to be simpler.
  • Ensembling: Ensembles are machine learning methods for combining predictions from multiple separate models.

The good one

Finally, looking at the middle graph it shows a pretty good predicted line. It covers the majority of the points in graph and also maintains the balance between bias and variance.

That is all for today.

ML – Python (VII) – Overfitting & Underfitting

ML – Python (VI) – Bias & Variance

Now, it is time to start digging in the theory of Machine Learning.

In the machine learning world, precision is everything. When we try to develop a model, we try to make it as much accurate as possible playing with the different parameters. But, the hard truth is that we can not build a one-hundred per cent accurate model due to we can not build a free of errors model. What we can do, it is trying to understand the possible sources of errors and this will help us to obtain a more precise model.

Types of errors

When we are talking about errors, we can find reducible and irreducible errors.

Irreducible errors are errors that cannot be reduced no matter what algorithm you apply. They are usually known as noise and, the can appear in our models due to multiple factors like an unknown variable, incomplete characteristics or a wrongly defined problem. It is important to mention that, no matter how good is our model, our data will always have some noise component or irreducible errors we can never remove.

Reducible errors have two components – bias and variance. This kind of errors derivate from the algorithm selection and the presence of bias or variance causes overfitting or underfitting of data.

Bias

Bias error is the difference between the expected prediction of our model and the real values or, saying it in a different way, how far are the predicted values from the actual values. High bias, predicted values are far off from the actual values, causes the algorithm to miss the relevant relationship between the input and output variable. When a model has a high bias then it implies that the model is too simple and does not capture the complexity of data thus underfitting the data. For example, if we try to adjust a linear regression to a set of data that has a non-linear pattern.

High bias implies that the model is too simple and does not capture the complexity of data thus underfitting the data. As examples, we have linear regression algorithms, logistic regression or linear discriminant analysis.

Low bias implies the opposite and it offers more flexibility. As examples, we have decision trees, k-nearest neighbour (KNN) and vector support machines.

Variance

It refers to the differences in the estimation of the function using different training data or, saying it in a different way, it tells us how scattered is the predicted value from the actual value. Variance occurs when the model performs well on the trained dataset but does not do well on a dataset that it is not trained on. Ideally, the result should not change too much from one set of data to another.

High variance causes overfitting that implies that the algorithm models random noise present in the training data, or that the algorithm is strongly dependent on the input data. It suggests big changes in the estimation of the function when the data changes. As an example, we have decision trees, k-nearest neighbour (KNN) and vector support machines.

Low variance suggests small changes in the estimation of the function when the data changes. As examples, we have linear regression, analysis of discrete linear systems and logic regression.

Bias–variance tradeoff

The objective of any machine learning algorithm is to achieve low bias and low variance, achieving at the same time a good performance predicting results. The bias-variance dilemma or bias-variance problem is the conflict in trying to simultaneously minimize these two sources of error that prevent supervised learning algorithms from generalizing beyond their training set. The bias opposite to the variance refers to the precision opposite to consistency of the trained models. Considering the combinations we can have:

  • High Bias Low Variance: Models are consistent but inaccurate on average. Tend to be less complex with a simple or rigid structure like linear regression or Bayesian linear regression.
  • Low Bias High variance: Models are somewhat accurate but inconsistent on averages. Tend to be more complex with a flexible structure like decision trees or k-nearest neighbour (KNN).
  • High Bias High Variance – Models are inaccurate and also inconsistent on average.
  • Low Bias Low Variance: This is the unicorn.

To build a good model we need to find a good balance between bias and variance that help us to minimise the total error. This is why to understand the bias and variance are fundamental to understand the model’s behaviour.

Detecting high bias or high variance

High Bias can be identified when we have:

  • High training error.
  • Validation error or test error is the same as training error.

High Variance can be identified when:

  • Low training error.
  • High validation error or high test error.

Fixing it

High bias is due to a simple model and we also see a high training error. To fix that we can do the following things:

  • Add more input features.
  • Add more complexity by introducing polynomial features.
  • Decrease Regularization term.

High variance is due to a model that tries to fit most of the training dataset points and hence gets more complex. To resolve the high variance issue we need to work on:

  • Getting more training data.
  • Reduce input features.
  • Increase Regularization term.

That is all for today. I hope the first theory article was not to hard to read. I will try to make them not too long and as concise as possible.

ML – Python (VI) – Bias & Variance

ML – Python (V) – scikit-learn

Finally, the last library we are going to see for now that will help us with our machine learning programs is going to be scikit-learn. This is probably one of the most useful libraries for Machine Learning in Python. It is an open-source library and it brings us a range of supervised and unsupervised learning algorithms.

This library includes the next libraries or packages:

  • NumPy: N-dimensional matrix library.
  • pandas: Data structures and analysis.
  • SciPy: Essential library for computer science.
  • Matplotlib: 2D data representation.
  • IP[y]: Improved interactive console.
  • SymPy: Symbolic mathematics.

Considering the extension and the fact that includes some of the libraries we have already explored, this article is going to be very short and without code examples. Basically, we are going to see a shortlist of basic functions or benefits the library offers us like:

  • Supervised learning algorithms: It brings us a variety of supervised algorithms.
  • Cross-validation: The library brings us instructions to implement some of the model’s precision verification methods.
  • Unsupervised learning algorithms: It brings us a variety of unsupervised algorithms.
  • Data sets: A miscellaneous collection of data sets.
  • Characteristic extraction and selection: It is very useful to extract characteristics from images and texts. In addition, it can help us to identify significant attributes.
  • Community: It has some community behind improving the library.

That’s all. Quick and simple. Let’s save some energy for the next article where we are going to start digging a little bit on Machine Learning theory.

ML – Python (V) – scikit-learn

ML – Python (IV) – Matplotlib

Continuing with the useful libraries we can find in the Python ecosystem, we have Matplotlib. It is a library that will help us present our data. It is a 2D graphics library.

With Matplotlib, we can use both Python or NumPy data structures but, it seems recommendable to use the NumPy data structures.

In the same way that the previous library we saw, Matplotlib does not come with the default installation and we need to install it in our system.

Installing Matplotlib

The installation is as simple as executing a command:

pip install -U matplotlib

After that, we will be able to draw some nice plots. As an example we can draw a basic one:

import matplotlib.pyplot as plt

a = [1, 2, 3, 4]
b = [11, 22, 33, 44]

plt.plot(a, b, color='blue', linewidth=3, label='line')
plt.legend()
plt.show()

You can find the code example here.

The result should be something like:

Matplotlib basic example

Details about the result view

The resulting view, see picture above, can contain different elements:

  • The main object is the window or main page, it is the top-level object for the rest of the elements.
  • You can create multiple independent objects.
  • Objects can have subtitles, legends and colour bars among others.
  • We can generate areas within the objects. They are where the data is represented with methods like ‘plot()‘ or ‘scatter()‘ and they can have associated labels.
  • Every area has an X-axis and a Y-axis representing numerical values. They have a scale, title and labels among others.

Matplotlib package structure

  • Matplotlib: The whole Python data visualization package.
  • Pyplot: It is a module of the Matplotlib package. Provides an interface to create objects and axis.
  • Pylab: It is a module of the Matplolib package. It is used to work with matrices. Its use is not recommended any more with the new IDEs and kernels.

Most common plot types

The most common plot types we can find are:

You can see more examples of available plots here.

With this, we finish a short overview of Matplolib and the main plots it can offer to us. Very interesting to draw them easily.

ML – Python (IV) – Matplotlib

ML – Python (III) – pandas

Another library in the Python ecosystem is pandas (PANel DAta). This library can help us to execute five common steps in data analysis:

  • Load data.
  • Data preparation.
  • Data manipulation.
  • Data modelling.
  • Data analysis.

The main panda structure is DataFrame. Two-dimensional size-mutable, potentially heterogeneous tabular data structure with labelled axes. It is composed of three elements: the data, the index and the columns. In addition, the names of columns and indexes can be specified.

Main library characteristics

  • The DataFrame object is fast and efficient.
  • Tools to load data in memory from different formats.
  • Data alignment and missing data management.
  • Remodelling and turning date sets.
  • Labelling, cut and indexation of big amounts of data.
  • Columns can be removed or inserted.
  • Data grouping for aggregation and transformation.
  • High performance for data union and merge.
  • Time-based series functionality.
  • It has three main structures:
    • Series: 1D structures.
    • DataFrame: 2D structures.
    • Panel: 3D structures.

Installing pandas

pandas library is not present in the default Python installation and it needs to be installed:

pip install -U pandas

pandas useful methods

Creating a Series

import pandas as pd

series = pd.Series({"UK": "London",
                    "Germany": "Berlin",
                    "France": "Paris",
                    "Spain": "Madrid"})

Creating a DataFrame

data = np.array([['', 'Col1', 'Col2'], ['Fila1', 11, 22], ['Fila2', 33, 44]])

You can find the code example here.

Without the boilerplate code:

import numpy as np
import pandas as pd

df = pd.DataFrame(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]))

Exploring a DataFrame

  • df.shape – DataFrame shape.
  • len(df.index) – DataFrame high.
  • df.describe() – DataFrame numeric statistics (count, mean, std, min, 25%, 50%, 75%, max).
  • df.mean() – Return the mean of the values for the requested axis.
  • df.corr() – Correlation of columns.
  • df.count() – Count of non-null values per column.
  • df.max() – Maximum value per column.
  • fd.min() – Minimum per column.
  • df.median() – Median value per column.
  • df.std() – Standard deviation per column.
  • df[0] – Select a DataFrame column (returned as a new DataFrame).
  • df[1, 2] – Select two DataFrame columns (returned as a new DataFrame).
  • df.iloc[0][2] – Select a value.
  • df.loc([0] – Select a column using the index.
  • df.iloc([0, :] – Select a column using the index.
  • pd.read_<file_type>() – Read from a file (pd.read_csv(‘train.csv’).
  • df.to_<file_type>() – Write to a file (pd.to_csv(‘new_train.csv’)).
  • df.isnull() – Verify is there are null values in the data set.
  • df.isnull().sum() – Return the sum of null values per column in the data set.
  • df.dropna() or df.dropna(axis = 1) – Remove rows or columns with missing data.
  • df.fillna(x) – Replace missing values with x (df.fillna(df.mean())).

And, this is all. This has been just a quick, very quick, review of the pandas library. I just recommend you to play around a bit more but, we will use it more in the future.

ML – Python (III) – pandas

ML – Python (II) – NumPy

As I have said before, one of the best advantages of Python is the huge community and amount of resources that supports it. One of these libraries is NumPy (NUMerical PYthon).

It is one of the main libraries to support scientific work with Python. It brings powerful data structures and implements matrices and multidimensional matrices.

As a short example we can see how to create a 1-dimension structure and a 2-dimensions structure:

import numpy as np

a = np.array([1, 2, 3])
...
b = np.array([(1, 2, 3), (4, 5, 6)])
...

You can find the code example here.

But, why should we use NumPy structures instead of Python structures?

There are a couple of main reasons:

  • NumPy arrays consumes less memory than Python lists.
  • NumPy arrays are faster in execution terms.

Because you do not need to trust me, let’s play a little bit with the code and run some informal benchmarks.

Let’s start with the memory assumption:

import sys
import numpy as np

s = range(1000)
print(sys.getsizeof(5) * len(s))
...
d = np.arange(1000)
print(d.size * d.itemsize)

You can find the code example here.

This gives us the next result:

Python list: 
28000
NumPy array: 
8000

As we can see, there is a big difference on the memory consumption.

Now, let’s do the same for the execution time. Again, we are going to write a small code snippet and execute an informal benchmark:

import time
import numpy as np

SIZE = 1_000_000

L1 = range(SIZE)
L2 = range(SIZE)
A1 = np.arange(SIZE)
A2 = np.arange(SIZE)

start = time.time()
result = [(x, y) for x, y in zip(L1, L2)]
print((time.time() - start) * 1000)
...
start = time.time()
result = A1 + A2
print((time.time() - start) * 1000)

You can find the code example here.

This gives us the next result:

Python list: 
316.49184226989746
NumPy array: 
65.60492515563965

Again, as we can see, the execution time for the NumPy structures is much better.

In addition to the speed and memory improvements, it is worth to point to the different syntax between Python and NumPy when writing the addition operation:

  • Python: [(x, y) for x, y in zip(L1, L2)]
  • NumPy: A1 + A2

As we can see, the difference is quite big. The second case, even if you know nothing about Python or NumPy, is very easy to understand.

Quick review of the NumPy API

  • Creating matrices
    • import numpy as np – Import the NumPy dependency.
    • np.array() – Creates a matrix.
    • np.ones((3, 4)) – Creates a matrix with a one in every position.
    • np.zeros((3, 4)) – Creates a matrix with a zero in every position.
    • np.random.random((3, 4)) – Creates a matrix with random values in every position.
    • np.empty((3, 4)) – Creates an empty matrix.
    • np.full((3, 4), 8) – Creates a matrix with a specified value in every position.
    • np.arange(0, 30, 5) – Creates a matrix with a distribution of values (from 0 to 30 every 5).
    • np.linspace(0, 2, 5) – Creates a matrix with a distribution of values (5 elements from 0 to 2).
    • np.eye(4, 4) – Creates an identity matrix.
    • np.identity(4) – Creates an identity matrix.
  • Inspect matrices
    • a.ndim – Matrix dimension.
    • a.dtype – Matrix data type.
    • a.size – Matrix size.
    • a.shape – Matrix shape.
    • a.reshape(3, 2) – Change the shape of a matrix.
    • a[3, 2] – Select a single element of the matrix.
    • a[0:, 2] – Extract the value in the column 2 from every row.
    • a.min(), a.max() and a.sum() – Basic operations over the matrix.
    • np.sqrt(a) – Square root of the matrix.
    • np.std(a) – Standard deviation of the matrix.
    • a + b, a – b, a * b and a / b – Basic operations between matrices.

And, this is all. This has been just a quick, very quick, review of the NumPy library. I just recommend you to play around a bit more but, we will use it more in the future.

ML – Python (II) – NumPy

ML – Python (I) – Introduction

We have been here, in the blog, talking about Machine Learning sometimes. The purpose of this series of articles is to go a little bit further and to explore a bit more the Machine Learning space and its relation with Python.

All the information in a more technical shape and the small scripts can be found at my GitHub account under the project python-ml.

One of the questions that it is worth to discuss is, why Python?

Available languages for Machine Learning

It is clear that you can use a lot of different languages to implement Machine Learning algorithms and programs but, looking at the space and popularity you can easily see a tendency and preference for four of them.

  • Python
    • It is the leader of the race right now due to the simplicity and its soft learning curve.
    • It is especially good and successful for beginners, in both, programming and Machine Learning.
    • The libraries ecosystem and community support are huge.
  • R
    • It is designed for statistical analysis and visualization, it is used frequently to unlock patterns in big data blocks.
    • With RStudio, developers can easily build algorithms and statistical visualization.
    • It is a free alternative to more expensive software like Matlab.
  • Matlab
    • It is fast, stable and secure for complex mathematics.
    • It is considered as a hardcore language for mathematicians and scientists.
  • Julia
    • Designed to deal with numerical analysis needs and computational science.
    • The base Julia library was integrated with C and Fortram open source libraries.
    • The collaboration between the Jupyter and Julia communities, it gives Julia a powerful UI.

Some important metrics to consider when choosing a language should be:

  • Speed.
  • Learning curve.
  • Cost.
  • Community support.
  • Productivity.

Here we can classify our languages as follows:

  • Speed: R is basically a statistical language and it is difficult to beat in this context.
  • Learning curve: Here depends on the person’s knowledge. R is closer to the functional languages as opposite to python that is closer to object-oriented languages.
  • Cost: Only Matlab is not a free language. The other languages are open source.
  • Community: All of them are very popular but, Python has a bigger community and amount of resources available.
  • Productivity: R for statistical analysis, Matlab for computational vision, bio-informatics or biology is the playground of Julia and, Python is the king for general tasks and multiple usages.

The decision, at the end of the day, is about a balance between all the characteristics seen above, our skills and the field we are or the tasks we want to implement.

In my case, I am going to choose Python as probably all of you have assumed because it is like a swiss knife and, at this point, the beginning, I think this is important. There is always time later to focus on other things or reduce the scope.

IDEs

There are multiple IDEs that support Python. As a very extended language, there are multiple tools and environments we can use. Here just take the one you like the more.

If you do not know any IDE or platform, there are two of them that a lot of Data Scientist use:

I do not know them. As a developer, I am more familiar with Visual Studio Code or IntelliJ, and I will be using one of them probably unless I discover some exciting functionality or advantage in one of the other.

ML – Python (I) – Introduction

New github repositories

One of the beautiful things that Computer Science has it that every single day appears something new to learn about or to investigate. That’s true that as a professional this make sometimes our jobs more challenging but, it is always a pleasure to have something to learn.

In this case, I have added two new repositories to my github account. Honestly, I know that the account is not very active and I do not have tons of code and snippets there, I prefer to write in the blog and not all the articles I write here generate code but, in the puntual occasions they do it, I use to upload the code to the github account.

In this days, I am learning a few things and they are generating some code. For this reason, I have decided to create a couple of new repositories.

On the one hand, I am preparing the CEH certification, I do not know yet if I am going to do the exam or not but I want to have the knowledge that involves. If you take a look to my old blog you will find some articles related with security and penetration testing. Together with this, I am learning a little bit of python focusing my learning in libraries that can help my with the automatization in this field. For this reason, I have started to read a book called “Python Penetration Testing Essentials” and I am writing some python code. To store properly all the code I am writing, I have decided to create a github repository in my account called “pythonPentesting“. In this repository, you can find the code I am writing in the meantime I am learning. In advance, I need to say that I do not know python, I am learning at the same time. Sometimes, the code is the one we can find in the book, sometimes I make some changes considering that it is an improvement or just for experimentation, and probably, sometimes I will be doing something very stupid but, any case, all is part of the learning process, right?

Repository URL: https://github.com/fjavierm/pythonPentesting

On the other hand, I have been writing code for some years, different languages, different platforms, different environments, but during the last years I have been focus in the Java / Java EE world (I am sure you could guess that for the content of my articles). In some projects I have been involved I have been a full-stack developer but, in one way or another, I was just writing basic JavaScript code, and not working with well known frameworks like Angular or Backbone, for example. Maybe, I have been involved in the development with in-house JavaScript frameworks but this is a complete different thing. The thing is that now I am a bit rusty when we are talking about front-end technologies and sometimes I have problems even to create a decent front-end for my little snippets or examples. I have decided to solve it  and to do it I have select Angular 2 and TypeScript. Why? I do not exactly know, I have been reading a lot, and it looks like it is an option that can match with me and my style. Will see in the future. In addition, both of them are quite mainstream (there is no discussion about that) and maybe can be useful in the future. In the same way that before, I have created a new github repository to store my code called “angular2AndTypeScript“. Let’s see how I progress. Nowadays, I am just following the course you can find in the “angular.io” page. You can find the course here.

Repository URL: https://github.com/fjavierm/angular2AndTypeScript

Let see how progress these learning initiatives.

See you.

New github repositories

Java REST API + cURL + python3

During the next lines, I am going to implement a very simple REST API using JavaEE 7 and Java SE 8 technologies, maven as build tool and GlassFish as application server. I am going to test this API with cURL and, I am going to consume this API using python3 using the Requests module.

Java EE 7 REST API

First, we need to create a maven project in our favorite IDE and add our dependencies to the pom.xml file

...
<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
 
<dependencies>
    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>eclipselink</artifactId>
        <version>2.5.2</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
        <version>2.5.2</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>
 
<build>
    <finalName>apicrud</finalName>
</build>
...

Second, we are going to create a persistence.xml file. In this case, we are not interested in how to configure a DB, then, we are going to use the default datasource that GlassFish provides us as default “jdbc/__default“. With all of this in mind, the file should look like this:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
        http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="ApiCrudPU" transaction-type="JTA">
        <jta-data-source>jdbc/__default</jta-data-source>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="javax.persistence.schema-generation.database.action" value="create"/>
        </properties>
    </persistence-unit>
</persistence>

Now, we need to create our Entity. In this case, I have chosen a simple one, User with three attributes:

  • id: Autogenerated id to identify the user.
  • name: User’s name.
  • email: User’s email.

The result should be something like:

package com.wordpress.binarycoders.apicrud;
 
import java.io.Serializable;
import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
 
@Entity
@Table (name = "users")
@NamedQueries ({
    @NamedQuery (name = User.FIND_ALL, query = "SELECT u FROM User u")
})
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class User implements Serializable {
     
    private static final long serialVersionUID = 1L;
     
    public static final String FIND_ALL = "User.findAll";
     
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
     
    @Column(name = "name")
    private String name;
     
    @Column(name = "email")
    private String email;
 
    /* Getters, Setters, equals and hashCode methods */   
}

The next step, it is to implement the boundary or service layer. Being a simple example, we can skip this layer, but I like to implement everything for learning purposes. This layer is going to be very simple, only the necessary object to perform the operation in the DB and the basic operations to implement a CRUD. The result looks like:

package com.wordpress.binarycoders.apicrud;
 
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.validation.constraints.NotNull;
 
@Stateless
public class UserService {
     
    @PersistenceContext
    private EntityManager em;
     
    public void create(@NotNull User user) {
        this.em.persist(user);
    }
     
    public User findById(@NotNull Long id) {
        return this.em.find(User.class, id);
    }
     
    public List<User> findAll() {
        TypedQuery<User> typedQuery = this.em.createNamedQuery(User.FIND_ALL, User.class);
 
        return typedQuery.getResultList();
    }
     
    public void update(@NotNull User user) {
        this.em.merge(user);
    }
     
    public void delete(@NotNull Long id) {
        this.em.remove(this.findById(id));
    }
}

To do all of this available to the world, we need to implement our REST API, and for this, we need to configure the REST capabilities in our system, piece of cake with the last version of Java EE. We just need to create a class to enable these capabilities:

package com.wordpress.binarycoders.apicrud;
 
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
 
@ApplicationPath("/rs")
public class ApplicationConfig extends Application {
     
}

And, finally, we need to implement our REST layer with the four actions that are going to allow us to perform the CRUD operations:

package com.wordpress.binarycoders.apicrud;
 
import java.net.URI;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
 
@Path("/users")
@Produces ({ MediaType.APPLICATION_JSON })
@Consumes ({ MediaType.APPLICATION_JSON })
@Stateless
public class UserEndPoint {
     
    @EJB
    private UserService service;
     
    @Context
    private UriInfo uriInfo;
     
    @GET
    public Response findAll() {
        List<User> users = this.service.findAll();
         
        GenericEntity<List<User>> list = new GenericEntity<List<User>>(users) {};
         
        return Response.ok(list).build();
    }
     
    @GET
    @Path("/{id}")
    public Response findById(@PathParam("id") Long id) {
        User user = this.service.findById(id);
         
        if (user == null) {
            throw new NotFoundException();
        }
         
        return Response.ok(user).build();
    }
     
    @POST
    public Response create(User user) {
        this.service.create(user);
         
        URI uri = uriInfo.getAbsolutePathBuilder().path(String.valueOf(user.getId())).build();
         
        return Response.created(uri).build();
    }
     
    @PUT
    public Response update(User user) {
        this.service.update(user);
         
        return Response.ok().build();
    }
     
    @DELETE
    @Path("/{id}")
    public Response delete(@PathParam("id") Long id) {
        this.service.delete(id);
         
        return Response.noContent().build();
    }
}

I think that in this point, assuming that everyone reading this, it is a developer and this is not an entry level post, all of you should be capable to understand everything has been written in the above lines. If there are things that you do not know or you do not understand due to a lack of information or your knowledge is not enough (all of us have been there), look at the note at the end of this post.

cURL test

Now, obviously, we need to test if our REST API is working properly. For this, we can implement some solution based on test frameworks or manual code but, due to the simplicity of the object User, it is enough with the cURL tool. To test our API we are going to perform these operations:

  • Select all the users
  • Create a user
  • Select the created user
  • Update the user
  • Delete the user

These operations can be performed with the next commands:

curl -i -H "Content-Type: application/json" http://localhost:8080/ApiCRUD/rs/users
curl -i -H "Content-Type: application/json" -X POST -d '{"name":"john","email":"john@example.org"}' http://localhost:8080/ApiCRUD/rs/users
curl -i -H "Content-Type: application/json" http://localhost:8080/ApiCRUD/rs/users/1
curl -i -H "Content-Type: application/json" -X PUT -d '{"id”:1,”name":"John Doe","email":"john.doe@example.org"}' http://localhost:8080/ApiCRUD/rs/users
curl -i -H "Content-Type: application/json" -X DELETE http://localhost:8080/ApiCRUD/rs/users/1

Everything should look well, and the appropriate HTTP codes should be received.

Python3 client

The last step today, it is to implement a very very simple python3 client to consume our API. This is going to be a basic script to invoke the CRUD operations available in the API.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
 
import requests
import json
 
URL = 'http://localhost:8080/ApiCRUD/rs/users'
 
def getUsers():
    print('Get users...\n')
 
    response = requests.get(URL)
 
    assert response.status_code == 200
 
    users = response.json()
    print(json.dumps(users, indent = 4, separators = (',', ':')))
 
def getUser(location):
    print('Get single user ...\n')
 
    response = requests.get(location)
 
    assert response.status_code == 200
 
    users = response.json()
    print(json.dumps(users, indent = 4, separators = (',', ':')))
 
def createUser():
    print('Creating user...\n')
 
    headers = {'content-type': 'application/json'}
    user = {"name": "John Doe", "email": "john.doe@example.org"}
    response = requests.post(URL, data = json.dumps(user), headers = headers)
 
    assert response.status_code == 201
 
    print('Location: ' + response.headers['location'])
 
    return response.headers['location']
 
def updateUser(location):
    print('Updating user...')
 
    loc = location.split('/')
 
    headers = {'content-type': 'application/json'}
    user = {"id": loc[-1], "name": "Jane Doe", "email": "jane.doe@example.org"}
    response = requests.put(URL, data = json.dumps(user), headers = headers)
 
    assert response.status_code == 200
 
def deleteUser(location):
    print('Deleting user...')
 
    response = requests.delete(location)
 
    assert response.status_code == 204
 
    print('Checking delete operation')
    response = requests.get(location)
 
    assert response.status_code == 404
 
def main():
    getUsers()
    location = createUser()
    getUser(location)
    updateUser(location)
    getUser(location)
    deleteUser(location)
 
if __name__ == "__main__":
    main()

And that’s all. Now, we have a little REST AP, a python3 client and a basic knowledge about how to use cURL to test it.

See you.

You can find the code for the REST API available here.

Note: All the content in this post will be splitter and explained in future post, one for each one of the three big point explained in here: Java EE 7 REST API creation, cURL test and python3 REST client.

Java REST API + cURL + python3

Python port scanner

Today, we are going to implement a simple port scanner implemented in python 3. The code is quite simple, and I think that it doesn’t need any explanation.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
 
from functools import partial
from multiprocessing import Pool
import socket
import optparse
 
DEFAULT_CORE_NUMBER = 2
 
 
def ping(host, port):
    try:
        socket.socket().connect((host, port))
        return port
    except socket.error as err:
        return False
 
 
def scanPorts(host, ports, cores):
    p = Pool(cores)
    ping_host = partial(ping, host)
 
    return filter(bool, p.map(ping_host, ports))
 
 
def main():
    parser = optparse.OptionParser('%prog -t <target host> -p <target port(s)> -n <number of cores>')
    parser.add_option('-t', dest='host', type='string', help='Specify the target host')
    parser.add_option('-p', dest='ports', type='string', help='Specify the target port(s); Separate them by commas.')
    parser.add_option('-n', dest='cores', type='int', help='Specify the number of CPU cores do you want to use.')
 
    (options, args) = parser.parse_args()
 
    if (options.host == None):
        print(parser.usage)
        exit(0)
    else:
        host = str(options.host)
 
    if (options.ports == None):
        ports = range(1, 65536)
    else:
        ports = list(map(int, str(options.ports).split(',')))
 
    if (options.cores == None):
        cores = DEFAULT_CORE_NUMBER
    else:
        cores = options.cores
 
    print('\nScanning ports on ' + host + ' ...')
 
    portsScanned = list(scanPorts(host, ports, cores))
 
    print(str(len(portsScanned)) + ' ports available.')
    print(portsScanned)
 
    print('\nDone.')
 
 
if __name__ == "__main__":
    main()

The script has three different options:

  • -t: Specify the target host. It is a mandatory option.
  • -p: Specify target ports.
  • -n: Specify the number of cores that are going to be used.

We can see some invocation examples:

scanner.py
scanner.py -t 127.0.0.1
scanner.py -t 127.0.0.1 -p 21,80 -n 2

See you.

Python port scanner