scikit-learn/examples/applications/plot_species_distribution_m...

211 lines
7.2 KiB
Python
Raw Normal View History

"""
=============================
Species distribution modeling
=============================
Modeling species' geographic distributions is an important
problem in conservation biology. In this example we
model the geographic distribution of two south american
mammals given past observations and 14 environmental
variables. Since we have only positive examples (there are
no unsuccessful observations), we cast this problem as a
density estimation problem and use the `OneClassSVM` provided
by the package `sklearn.svm` as our modeling tool.
The dataset is provided by Phillips et. al. (2006).
2011-12-20 01:29:00 +08:00
If available, the example uses
`basemap <http://matplotlib.sourceforge.net/basemap/doc/html/>`_
to plot the coast lines and national boundaries of South America.
The two species are:
2011-12-20 01:29:00 +08:00
- `"Bradypus variegatus"
<http://www.iucnredlist.org/apps/redlist/details/3038/0>`_ ,
the Brown-throated Sloth.
2011-12-20 01:29:00 +08:00
- `"Microryzomys minutus"
<http://www.iucnredlist.org/apps/redlist/details/13408/0>`_ ,
also known as the Forest Small Rice Rat, a rodent that lives in Peru,
Colombia, Ecuador, Peru, and Venezuela.
2011-12-21 08:15:15 +08:00
References
----------
* `"Maximum entropy modeling of species geographic distributions"
<http://www.cs.princeton.edu/~schapire/papers/ecolmod.pdf>`_
S. J. Phillips, R. P. Anderson, R. E. Schapire - Ecological Modelling,
190:231-259, 2006.
"""
2011-12-21 08:15:15 +08:00
# Authors: Peter Prettenhoer <peter.prettenhofer@gmail.com>
# Jake Vanderplas <vanderplas@astro.washington.edu>
#
# License: BSD Style.
from time import time
import numpy as np
2011-12-21 03:16:09 +08:00
import pylab as pl
2011-12-21 03:16:09 +08:00
from sklearn.datasets.base import Bunch
2011-12-21 08:15:15 +08:00
from sklearn.datasets import fetch_species_distributions
from sklearn.datasets.species_distributions import construct_grids
from sklearn import svm, metrics
2011-12-21 03:16:09 +08:00
# if basemap is available, we'll use it.
# otherwise, we'll improvise later...
try:
from mpl_toolkits.basemap import Basemap
basemap = True
except ImportError:
basemap = False
2011-12-21 08:15:15 +08:00
print __doc__
2011-12-21 03:16:09 +08:00
def create_species_bunch(species_name,
train, test,
coverages, xgrid, ygrid):
"""
create a bunch with information about a particular organism
2011-12-21 03:16:09 +08:00
This will use the test/train record arrays to extract the
data specific to the given species name.
"""
bunch = Bunch(name=' '.join(species_name.split("_")[:2]))
2011-05-11 22:55:00 +08:00
2011-12-21 03:16:09 +08:00
points = dict(test=test, train=train)
2011-12-21 03:16:09 +08:00
for label, pts in points.iteritems():
# choose points associated with the desired species
pts = pts[pts['species'] == species_name]
bunch['pts_%s' % label] = pts
2011-12-21 03:16:09 +08:00
# determine coverage values for each of the training & testing points
ix = np.searchsorted(xgrid, pts['dd long'])
iy = np.searchsorted(ygrid, pts['dd lat'])
bunch['cov_%s' % label] = coverages[:, -iy, ix].T
2011-12-21 03:16:09 +08:00
return bunch
2011-05-11 22:55:00 +08:00
2011-12-21 08:15:15 +08:00
def plot_species_distribution(species=["bradypus_variegatus_0",
"microryzomys_minutus_0"]):
"""
2011-12-21 03:16:09 +08:00
Plot the species distribution.
"""
2011-12-21 08:15:15 +08:00
if len(species) > 2:
print ("Note: when more than two species are provided, only "
"the first two will be used")
2011-12-21 03:16:09 +08:00
t0 = time()
# Load the compressed data
2011-12-21 08:15:15 +08:00
data = fetch_species_distributions()
2011-12-21 03:16:09 +08:00
# Set up the data grid
2011-12-21 08:15:15 +08:00
xgrid, ygrid = construct_grids(data)
2011-12-21 03:16:09 +08:00
# The grid in x,y coordinates
X, Y = np.meshgrid(xgrid, ygrid[::-1])
2011-12-21 08:15:15 +08:00
2011-12-21 03:16:09 +08:00
# create a bunch for each species
2011-12-21 08:15:15 +08:00
BV_bunch = create_species_bunch(species[0],
data.train, data.test,
data.coverages, xgrid, ygrid)
MM_bunch = create_species_bunch(species[1],
data.train, data.test,
data.coverages, xgrid, ygrid)
2011-12-21 03:16:09 +08:00
# background points (grid coordinates) for evaluation
np.random.seed(13)
2011-12-21 08:15:15 +08:00
background_points = np.c_[np.random.randint(low=0, high=data.Ny,
2011-12-21 03:16:09 +08:00
size=10000),
2011-12-21 08:15:15 +08:00
np.random.randint(low=0, high=data.Nx,
2011-12-21 03:16:09 +08:00
size=10000)].T
2011-12-21 08:15:15 +08:00
# We'll make use of the fact that coverages[6] has measurements at all
# land points. This will help us decide between land and water.
land_reference = data.coverages[6]
2011-12-21 03:16:09 +08:00
# Fit, predict, and plot for each species.
2011-12-21 08:15:15 +08:00
for i, species in enumerate([BV_bunch, MM_bunch]):
2011-12-21 03:16:09 +08:00
print "_" * 80
print "Modeling distribution of species '%s'" % species.name
2011-12-21 08:15:15 +08:00
2011-12-21 03:16:09 +08:00
# Standardize features
mean = species.cov_train.mean(axis=0)
std = species.cov_train.std(axis=0)
train_cover_std = (species.cov_train - mean) / std
# Fit OneClassSVM
2011-12-21 08:15:15 +08:00
print " - fit OneClassSVM ... ",
2011-12-21 03:16:09 +08:00
clf = svm.OneClassSVM(nu=0.1, kernel="rbf", gamma=0.5)
clf.fit(train_cover_std)
print "done. "
# Plot map of South America
2011-12-21 08:15:15 +08:00
pl.subplot(1, 2, i + 1)
2011-12-21 03:16:09 +08:00
if basemap:
2011-12-21 08:15:15 +08:00
print " - plot coastlines using basemap"
m = Basemap(projection='cyl', llcrnrlat=Y.min(),
urcrnrlat=Y.max(), llcrnrlon=X.min(),
urcrnrlon=X.max(), resolution='c')
2011-12-21 03:16:09 +08:00
m.drawcoastlines()
m.drawcountries()
else:
2011-12-21 08:15:15 +08:00
print " - plot coastlines from coverage"
pl.contour(X, Y, land_reference,
levels=[-9999], colors="k",
linestyles="solid")
2011-12-21 03:16:09 +08:00
pl.xticks([])
pl.yticks([])
2011-12-21 08:15:15 +08:00
print " - predict species distribution"
2011-12-21 03:16:09 +08:00
# Predict species distribution using the training data
2011-12-21 08:15:15 +08:00
Z = np.ones((data.Ny, data.Nx), dtype=np.float64)
2011-12-21 03:16:09 +08:00
2011-12-21 08:15:15 +08:00
# We'll predict only for the land points.
idx = np.where(land_reference > -9999)
coverages_land = data.coverages[:, idx[0], idx[1]].T
2011-12-21 03:16:09 +08:00
pred = clf.decision_function((coverages_land - mean) / std)[:, 0]
Z *= pred.min()
Z[idx[0], idx[1]] = pred
levels = np.linspace(Z.min(), Z.max(), 25)
2011-12-21 08:15:15 +08:00
Z[land_reference == -9999] = -9999
2011-12-21 03:16:09 +08:00
# plot contours of the prediction
pl.contourf(X, Y, Z, levels=levels, cmap=pl.cm.Reds)
2011-12-21 03:16:09 +08:00
pl.colorbar(format='%.2f')
# scatter training/testing points
pl.scatter(species.pts_train['dd long'], species.pts_train['dd lat'],
s=2 ** 2, c='black',
marker='^', label='train')
pl.scatter(species.pts_test['dd long'], species.pts_test['dd lat'],
s=2 ** 2, c='black',
marker='x', label='test')
pl.legend()
pl.title(species.name)
pl.axis('equal')
# Compute AUC w.r.t. background points
pred_background = Z[background_points[0], background_points[1]]
2011-12-21 08:15:15 +08:00
pred_test = clf.decision_function((species.cov_test - mean)
/ std)[:, 0]
2011-12-21 03:16:09 +08:00
scores = np.r_[pred_test, pred_background]
y = np.r_[np.ones(pred_test.shape), np.zeros(pred_background.shape)]
2011-12-21 08:15:15 +08:00
fpr, tpr, thresholds = metrics.roc_curve(y, scores)
roc_auc = metrics.auc(fpr, tpr)
2011-12-21 03:16:09 +08:00
pl.text(-35, -70, "AUC: %.3f" % roc_auc, ha="right")
2011-12-21 08:15:15 +08:00
print "\n Area under the ROC curve : %f" % roc_auc
2011-12-21 03:16:09 +08:00
2011-12-21 08:15:15 +08:00
print "\ntime elapsed: %.2fs" % (time() - t0)
2011-12-21 03:16:09 +08:00
plot_species_distribution()
pl.show()