Explainable AI Recipes: Implement Solutions to Model Explainability and Interpretability with Python 1st Edition Pradeepta Mishra download
Explainable AI Recipes: Implement Solutions to Model Explainability and Interpretability with Python 1st Edition Pradeepta Mishra download
https://ebookmass.com/product/explainable-ai-recipes-
implement-solutions-to-model-explainability-and-
interpretability-with-python-1st-edition-pradeepta-mishra-2/
https://ebookmass.com/product/productionizing-ai-how-to-deliver-
ai-b2b-solutions-with-cloud-and-python-1st-edition-barry-walsh/
https://ebookmass.com/product/introduction-to-responsible-ai-
implement-ethical-ai-using-python-1st-edition-manure/
https://ebookmass.com/product/productionizing-ai-how-to-deliver-
ai-b2b-solutions-with-cloud-and-python-1st-edition-barry-walsh-2/
PyTorch Recipes: A Problem-Solution Approach to Build,
Train and Deploy Neural Network Models, 2nd Edition
Pradeepta Mishra
https://ebookmass.com/product/pytorch-recipes-a-problem-solution-
approach-to-build-train-and-deploy-neural-network-models-2nd-edition-
pradeepta-mishra/
https://ebookmass.com/product/time-series-algorithms-recipes-
implement-machine-learning-and-deep-learning-techniques-with-python-
akshay-r-kulkarni/
https://ebookmass.com/product/introduction-to-datafication-implement-
datafication-using-ai-and-ml-algorithms-shivakumar-r-goniwada-2/
https://ebookmass.com/product/introduction-to-datafication-implement-
datafication-using-ai-and-ml-algorithms-shivakumar-r-goniwada/
https://ebookmass.com/product/introduction-to-prescriptive-ai-a-
primer-for-decision-intelligence-solutioning-with-python-akshay-
kulkarni/
Pradeepta Mishra
Explainable AI Recipes
Implement Solutions to Model Explainability and
Interpretability with Python
Pradeepta Mishra
Bangalore, Karnataka, India
Apress Standard
The publisher, the authors, and the editors are safe to assume that the
advice and information in this book are believed to be true and accurate
at the date of publication. Neither the publisher nor the authors or the
editors give a warranty, expressed or implied, with respect to the
material contained herein or for any errors or omissions that may have
been made. The publisher remains neutral with regard to jurisdictional
claims in published maps and institutional affiliations.
Industries in which artificial intelligence has been applied include banking, financial services, insurance,
healthcare, manufacturing, retail, and pharmaceutical. There are regulatory requirements in some of these
industries where model explainability is required. Artificial intelligence involves classifying objects,
recognizing objects to detect fraud, and so forth. Every learning system requires three things: input data,
processing, and an output. If the performance of any learning system improves over time by learning from
new examples or data, it is called a machine learning system. When the number of features for a machine
learning task increases or the volume of data increases, it takes a lot of time to apply machine learning
techniques. That’s when deep learning techniques are used.
Figure 1-1 represents the relationships between artificial intelligence, machine learning, and deep
learning.
After preprocessing and feature creation, you can observe hundreds of thousands of features that need
to be computed to produce output. If we train a machine learning supervised model, it will take significant
time to produce the model object. To achieve scalability in this task, we need deep learning algorithms, such
as a recurrent neural network. This is how artificial intelligence is connected to deep learning and machine
learning.
In the classical predictive modeling scenario, a function is identified, and the input data is usually fit to
the function to produce the output, where the function is usually predetermined. In a modern predictive
modeling scenario, the input data and output are both shown to a group of functions, and the machine
identifies the best function that approximates well to the output given a particular set of input. There is a
need to explain the output of a machine learning and deep learning model in performing regression- and
classification-related tasks. These are the reasons why explainability is required:
Trust: To gain users’ trust on the predicted output
Reliability: To make the user rely on the predicted output
Regulatory: To meet regulatory and compliance requirements
Adoption: To increase AI adoption among the users
Fairness: To remove any kind of discrimination in prediction
Accountability: To establish ownership of the predictions
There are various ways that explainability can be achieved using statistical properties, probabilistic
properties and associations, and causality among the features. Broadly, the explanations of the models can
be classified into two categories, global explanations and local explanations. The objective of local
explanation is to understand the inference generated for one sample at a time by comparing the nearest
possible data point; global explanation provides an idea about the overall model behavior.
The goal of this chapter is to introduce how to install various explainability libraries and interpret the
results generated by those explainability libraries.
Solution
The solution to this problem is to use the simple pip or conda option.
How It Works
Let’s take a look at the following script examples. The SHAP Python library is based on a game theoretic
approach that attempts to explain local and as well as global explanations.
or
Solution
You can install the LIME library using pip or conda.
How It Works
Let’s take a look at the following example script:
or
Solution
If you want to use a combination of functions from both the LIME library and the SHAP library, then you can
use the SHAPASH library. You just have to install it, which is simple.
How It Works
Let’s take a look at the following code to install SHAPASH. This is not available on the Anaconda distribution;
the only way to install it is by using pip.
Solution
Since this is a Python library, you can use pip.
How It Works
Let’s take a look at the following script:
Solution
Skater is an open-source framework to enable model interpretation for various kinds of machine learning
models. The Python-based Skater library provides both global and local interpretations and can be installed
using pip.
How It Works
Let’s take a look at the following script:
Solution
Skope-rules offers a trade-off between the interpretability of a decision tree and the modeling power of a
random forest model. The solution is simple; you use the pip command.
How It Works
Let’s take a look at the following code:
Solution
The explainability method depends on who is the consumer of the model output, if it is the business or
senior management then the explainability should be very simple and plain English without any
mathematical formula and if the consumer of explainability is data scientists and machine learning
engineers then the explanations may include the mathematical formulas.
How It Works
The levels of transparency of the machine learning models can be categorized into three buckets, as shown
in Figure 1-2.
Textual explanations require explaining the mathematical formula in plain English, which can help
business users or senior management. The interpretations can be designed based on model type and model
variant and can draw inferences from the model outcome. A template to draw inferences can be designed
and mapped to the model types, and then the templates can be filled in using some natural language
processing methods.
A visual explainability method can be used to generate charts, graphs such as dendrograms, or any other
types of graphs that best explain the relationships. The tree-based methods use if-else conditions on the
back end; hence, it is simple to show the causality and the relationship.
Using common examples and business scenarios from day-to-day operations and drawing parallels
between them can also be useful.
Which method you should choose depends on the problem that needs to be solved and the consumer of
the solution where the machine learning model is being used.
Conclusion
In various AI projects and initiatives, the machine learning models generate predictions. Usually, to trust the
outcomes of a model, a detailed explanation is required. Since many people are not comfortable explaining
the machine learning model outcomes, they cannot reason out the decisions of a model, and thereby AI
adoption is restricted. Explainability is required from regulatory stand point as well as auditing and
compliance point of view. In high-risk use cases such as medical imaging and object detection or pattern
recognition, financial prediction and fraud detection, etc., explainability is required to explain the decisions
of the machine learning model.
In this chapter, we set up the environment by installing various explainable AI libraries. Machine
learning model interpretability and explainability are the key focuses of this book. We are going to use
Python-based libraries, frameworks, methods, classes, and functions to explain the models.
In the next chapter, we are going to look at the linear models.
© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2023
P. Mishra, Explainable AI Recipes
https://doi.org/10.1007/978-1-4842-9029-3_2
A supervised learning model is a model that is used to train an algorithm to map input data to output data. A
supervised learning model can be of two types: regression or classification. In a regression scenario, the
output variable is numerical, whereas with classification, the output variable is binary or multinomial. A
binary output variable has two outcomes, such as true and false, accept and reject, yes and no, etc. In the
case of multinomial output variables, the outcome can be more than two, such as high, medium, and low. In
this chapter, we are going to use explainable libraries to explain a regression model and a classification
model, while training a linear model.
In the classical predictive modeling scenario, a function has been identified, and the input data is usually
fit to the function to produce the output, where the function is usually predetermined. In a modern
predictive modeling scenario, the input data and output are both shown to a group of functions, and the
machine identifies the best function that approximates well to the output given a particular set of input.
There is a need to explain the output of machine learning and deep learning models when performing
regression and classification tasks. Linear regression and linear classification models are simpler to explain.
The goal of this chapter is to introduce various explainability libraries for linear models such as feature
importance, partial dependency plot, and local interpretation.
Recipe 2-1. SHAP Values for a Regression Model on All Numerical Input
Variables
Problem
You want to explain a regression model built on all the numeric features of a dataset.
Solution
A regression model on all the numeric features is trained, and then the trained model will be passed through
SHAP to generate global explanations and local explanations.
How It Works
Let’s take a look at the following script. The Shapely value can be called the SHAP value. It is used to explain
the model. It uses the impartial distribution of predictions from a cooperative game theory to attribute a
feature to the model’s predictions. Input features from the dataset are considered as players in the game.
The models function is considered the rules of the game. The Shapely value of a feature is computed based
on the following steps:
1. SHAP requires model retraining on all feature subsets; hence, usually it takes time if the explanation has
to be generated for larger datasets.
2. Identify a feature set from a list of features (let’s say there are 15 features, and we can select a subset
with 5 features).
3. For any particular feature, two models using the subset of features will be created, one with the feature
and another without the feature.
4. Then the prediction differences will be computed.
5. The differences in prediction are computed for all possible subsets of features.
6. The weighted average value of all possible differences is used to populate the feature importance.
If the weight of the feature is 0.000, then we can conclude that the feature is not important and has not
joined the model. If it is not equal to 0.000, then we can conclude that the feature has a role to play in the
prediction process.
We are going to use a dataset from the UCI machine learning repository. The URL to access the dataset is
as follows:
https://archive.ics.uci.edu/ml/datasets/Appliances+energy+prediction
The objective is to predict the appliances’ energy use in Wh, using the features from sensors. There are
27 features in the dataset, and here we are trying to understand what features are important in predicting
the energy usage. See Table 2-1.
import pandas as pd
import shap
import sklearn
print("Model coefficients:\n")
for i in range(X.shape[1]):
print(X.columns[i], "=", model.coef_[i].round(5))
Model coefficients:
lights = 1.98971
T1 = -0.60374
RH_1 = 15.15362
T2 = -17.70602
RH_2 = -13.48062
T3 = 25.4064
RH_3 = 4.92457
T4 = -3.46525
RH_4 = -0.17891
T5 = -0.02784
RH_5 = 0.14096
T6 = 7.12616
RH_6 = 0.28795
T7 = 1.79463
RH_7 = -1.54968
T8 = 8.14656
RH_8 = -4.66968
T9 = -15.87243
RH_9 = -0.90102
T_out = -10.22819
Press_mm_hg = 0.13986
RH_out = -1.06375
Windspeed = 1.70364
Visibility = 0.15368
Tdewpoint = 5.0488
rv1 = -0.02078
rv2 = -0.02078
pd.DataFrame(np.round(shap_values.values,3)).head(3)
pd.DataFrame(np.round(shap_values.data,3)).head(3)
Solution
The solution to this problem is to use the partial dependency method (partial_dependence_plot)
from the model.
How It Works
Let’s take a look at the following example. There are two ways to get the partial dependency plot, one with a
particular data point superimposed and the other without any reference to the data point. See Figure 2-1.
# make a standard partial dependence plot for lights on predicted output for
row number 20 from the training dataset.
sample_ind = 20
shap.partial_dependence_plot(
"lights", model.predict, X, model_expected_value=True,
feature_expected_value=True, ice=False,
shap_values=shap_values[sample_ind:sample_ind+1,:]
)
Figure 2-1 Correlation between feature light and predicted output of the model
The partial dependency plot is a way to explain the individual predictions and generate local
interpretations for the sample selected from the dataset; in this case, the sample 20th record is selected from
the training dataset. Figure 2-1 shows the partial dependency superimposed with the 20th record in red.
shap.partial_dependence_plot(
"lights", model.predict, X, ice=False,
model_expected_value=True, feature_expected_value=True
)
Figure 2-2 Partial dependency plot between lights and predicted outcome from the model
The local interpretation for record number 20 from the training dataset is displayed in Figure 2-3. The
predicted output for the 20th record is 140 Wh. The most influential feature impacting the 20th record is
RH_1, which is the humidity in the kitchen area in percentage, and RH_2, which is the humidity in the living
room area. On the bottom of Figure 2-3, there are 14 features that are not very important for the 20th
record’s predicted value.
X[20:21]
model.predict(X[20:21])
array([140.26911466])
Recipe 2-3. SHAP Feature Importance for Regression Model with All
Numerical Input Variables
Problem
You want to calculate the feature importance using the SHAP values.
Solution
The solution to this problem is to use SHAP absolute values from the model.
How It Works
Let’s take a look at the following example. SHAP values can be used to show the global importance of
features. Importance features means features that have a larger importance in predicting the output.
print(shap_importance)
col_name feature_importance_vals
2 RH_1 49.530061
19 T_out 43.828847
4 RH_2 42.911069
5 T3 41.671587
11 T6 34.653893
3 T2 31.097282
17 T9 26.607721
16 RH_8 19.920029
24 Tdewpoint 17.443688
21 RH_out 13.044643
6 RH_3 13.042064
15 T8 12.803450
0 lights 11.907603
12 RH_6 7.806188
14 RH_7 6.578015
7 T4 5.866801
22 Windspeed 3.361895
13 T7 3.182072
18 RH_9 3.041144
23 Visibility 1.385616
10 RH_5 0.855398
20 Press_mm_hg 0.823456
1 T1 0.765753
8 RH_4 0.642723
25 rv1 0.260885
26 rv2 0.260885
9 T5 0.041905
All the feature importance values are not scaled; hence, sum of values from all features will not be
totaling 100.
The beeswarm chart in Figure 2-4 shows the impact of SHAP values on model output. The blue dot
shows a low feature value, and a red dot shows a high feature value. Each dot indicates one data point from
the dataset. The beeswarm plot shows the distribution of feature values against the SHAP values.
shap.plots.beeswarm(shap_values)
Recipe 2-4. SHAP Values for a Regression Model on All Mixed Input Variables
Problem
How do you estimate SHAP values when you introduce the categorical variables along with the numerical
variables, which is a mixed set of input features.
Solution
The solution is that the mixed input variables that have numeric features as well as categorical or binary
features can be modeled together. As the number of features increases, the time to compute all the
permutations will also increase.
How It Works
We are going to use an automobile public dataset with some modifications. The objective is to predict the
price of a vehicle given the features such as make, location, age, etc. It is a regression problem that we are
going to solve using a mix of numeric and categorical features.
df =
pd.read_csv('https://raw.githubusercontent.com/pradmishra1/PublicDatasets/main
df.head(3)
df.columns
Index(['Price', 'Make', 'Location', 'Age', 'Odometer', 'FuelType', 'Transmissi
'Mileage', 'EngineCC', 'PowerBhp'], dtype='object')
We cannot use string-based features or categorical features in the model directly as matrix multiplication
is not possible on string features; hence, the string-based features need to be transformed into dummy
variables or binary features with 0 and 1 flags. The transformation step is skipped here because many data
scientists already know how to do this data transformation. We are importing another transformed dataset
directly.
df_t =
pd.read_csv('https://raw.githubusercontent.com/pradmishra1/PublicDatasets/main
del df_t['Unnamed: 0']
df_t.head(3)
df_t.columns
Index(['Price', 'Age', 'Odometer', 'mileage', 'engineCC', 'powerBhp', 'Locatio
'Location_Chennai', 'Location_Coimbatore', 'Location_Delhi', 'Location_Hyderab
'Location_Kochi', 'Location_Kolkata', 'Location_Mumbai', 'Location_Pune', 'Fue
'FuelType_Electric', 'FuelType_LPG', 'FuelType_Petrol', 'Transmission_Manual',
Above', 'OwnerType_Second', 'OwnerType_Third'], dtype='object')
import pandas as pd
import shap
import sklearn
print("Model coefficients:\n")
for i in range(X.shape[1]):
print(X.columns[i], "=", model.coef_[i].round(5))
Model coefficients:
Age = -0.92281
Odometer = 0.0
mileage = -0.07923
engineCC = -4e-05
powerBhp = 0.1356
Location_Bangalore = 2.00658
Location_Chennai = 0.94944
Location_Coimbatore = 2.23592
Location_Delhi = -0.29837
Location_Hyderabad = 1.8771
Location_Jaipur = 0.8738
Location_Kochi = 0.03311
Location_Kolkata = -0.86024
Location_Mumbai = -0.81593
Location_Pune = 0.33843
FuelType_Diesel = -1.2545
FuelType_Electric = 7.03139
FuelType_LPG = 0.79077
FuelType_Petrol = -2.8691
Transmission_Manual = -2.92415
OwnerType_Fourth +ACY- Above = 1.7104
OwnerType_Second = -0.55923
OwnerType_Third = 0.76687
To compute the SHAP values, we can use the explainer function with the training dataset X and model
predict function. The SHAP value calculation happens using a permutation approach; it took 5 minutes.
import numpy as np
pd.DataFrame(np.round(shap_values.values,3)).head(3)
0
0 11.933
1 11.933
2 11.933
pd.DataFrame(np.round(shap_values.data,3)).head(3)
Recipe 2-5. SHAP Partial Dependency Plot for Regression Model for Mixed
Input
Problem
You want to plot the partial dependency plot and interpret the graph for numeric and categorical dummy
variables.
Solution
The partial dependency plot shows the correlation between the feature and the predicted output of the
target variables. There are two ways we can showcase the results, one with a feature and expected value of
the prediction function and the other with superimposing a data point on the partial dependency plot.
How It Works
Let’s take a look at the following example (see Figure 2-5):
shap.partial_dependence_plot(
"powerBhp", model.predict, X, ice=False,
model_expected_value=True, feature_expected_value=True
)
Figure 2-5 Partial dependency plot for powerBhp and predicted price of the vehicle
The linear blue line shows the positive correlation between the price and the powerBhp. The powerBhp
is a strong feature. The higher the bhp, the higher the price of the car. This is a continuous or numeric
feature; let’s look at the binary or dummy features. There are two dummy features if the car is registered in a
Bangalore location or in a Kolkata location as dummy variables. See Figure 2-6.
shap.partial_dependence_plot(
"Location_Bangalore", model.predict, X, ice=False,
model_expected_value=True, feature_expected_value=True
)
If the location of the car is Bangalore, then the price would be higher, and vice versa. See Figure 2-7.
shap.partial_dependence_plot(
"Location_Kolkata", model.predict, X, ice=False,
model_expected_value=True, feature_expected_value=True
)
Figure 2-7 Dummy variable Location_Kolkata versus SHAP value
If the location is Kolkata, then the price is expected to be lower. The reason for the difference between
the two locations is in the data that is being used to train the model. The previous three figures show the
global importance of a feature versus the prediction function. As an example, only two features are taken
into consideration; we can use all features one by one and display many graphs to get more understanding
about the predictions.
Now let’s look at a sample data point superimposed on a partial dependence plot to display local
explanations. See Figure 2-8.
The vertical dotted line shows the average powerBhp, and the horizontal dotted line shows the average
predicted value by the model. The small blue bar dropping from the black dot reflects the placement of
record number 20 from the dataset. Local interpretation means that for any sample record from the dataset,
we should be able to explain the predictions. Figure 2-9 shows the importance of features corresponding to
each record in the dataset.
Figure 2-9 Local interpretation of the 20th record and corresponding feature importance
For the 20th record, the predicted price is 22.542, the powerBhp stands out to be most important feature,
and manual transmission is the second most important feature.
X[20:21]
model.predict(X[20:21])
array([22.54213017])
Recipe 2-6. SHAP Feature Importance for a Regression Model with All Mixed
Input Variables
Problem
You want to get the global feature importance from SHAP values using mixed-input feature data.
Solution
The solution to this problem is to use absolute values and sort them in descending order.
How It Works
Let’s take a look at the following example:
Recipe 2-7. SHAP Strength for Mixed Features on the Predicted Output for
Regression Models
Problem
You want to know the impact of a feature on the model function.
Solution
The solution to this problem is to use a beeswarm plot that displays the blue and red points.
How It Works
Let’s take a look at the following example (see Figure 2-10). From the beeswarm plot there is a positive
relationship between powerBhp and positive SHAP value; however, there is a negative correlation between
the age of a car and the price of the car. As the feature value increases from a lower powerBhp value to a
higher powerBhp value, the shap value increases and vice versa. However, there is an opposite trend for the
age feature.
shap.plots.beeswarm(shap_values)
Solution
The solution to this problem is to use a numerical dataset and generate local and global explanations after
applying the standard scaler to the data.
How It Works
Let’s take a look at the following script:
import pandas as pd
df_lin_reg = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-
databases/00374/energydata_complete.csv')
del df_lin_reg['date']
#y is the dependent variable, that we need to predict
y = df_lin_reg.pop('Appliances')
# X is the set of input features
X = df_lin_reg
import pandas as pd
import shap
import sklearn
#create standardized features
scaler = sklearn.preprocessing.StandardScaler()
scaler.fit(X)
#transform the dataset
X_std = scaler.transform(X)
# a simple linear model initialized
model = sklearn.linear_model.LinearRegression()
1065 Archaeologia, xlii, 1869, pp. 39, 48-50; xlvi, 1881, pp. 450-
1, 456-8.
1069 Archaeol. Cambr., 6th ser., vi, 1906, pp. 266-7. Two forts
with defences of this kind are known in Peebles-shire.
1070 B. G., ii, 29, § 2; vi, 32, § 4. Cf. Mém. de la Soc. nat. des
ant. de France, 4e sér., ii, 1871, pp. 141-2.
1073 See p. 138, supra, and also Archaeologia, xlvi, 1881, pp.
438-9, 467; A. Pitt-Rivers, Excavations in Cranborne
Chase, ii, 238-9; Archaeol. Cambr., 5th ser., xvi, 1899, pp.
106-8, 130; xvii, 1900, pp. 189, 195, 206, 209; Archaeol.
Journal, lvii, 1900, pp. 52-6, 60-3, 66-7; Journ. Roy. Inst.
Cornwall, xvi, 1904, pp. 73-83; and Guide to the Ant. of
the Early Iron Age (Brit. Museum), pp. 122-4.
1076 See Proc. Soc. Ant. Scot., xxix, 1895, pp. 131, 149-50.
1077 B. G., vii, 22.
1078 Proc. Soc. Ant. Scot., xxv, 1891, pp. 428, 438, 440, 444-5.
1079 Ib., xxxiii, 1899, pp. 15, 20-3, 26-32; xxxiv, 1900, p. 74. A
similar method of fortification was practised by the
Dacians (Congrès archéol. de France, 1874 1876, p. 444),
‘in the Danne-werk at Korborg, near Schleswig’ (A. Pitt-
Rivers, Excavations in Cranborne Chase, iii, 254), and in
Nassau (Rev. de synthèse hist., iii, 1901, p. 45).
1080 Reports Archit. Soc. of ... Lincoln, &c., xviii, 1885-6, pp.
53-61; Archaeologia, lii, 1890, pp. 382-4; Vict. Hist. of ...
Northampton, i, 147-9, 151-2. At Beansale and Claverdon
in Warwickshire there are camps which in many respects
resemble that of Hunsbury, but have not been excavated
(Vict. Hist. of ... Warwick, i, 350).
1082 Journ. Derbyshire Archaeol. and Nat. Hist. Soc., xiii, 1891,
pp. 194-9; xiv, 1892, pp. 247-8; xvii, 1895, p. 76; Vict.
Hist. of ... Derby, i, 231-42. Cf. Association franç. pour
l’avancement des sc., 32e sess., 1903, 2e partie, p. 890.
1083 Vict. Hist. of ... Bedford, i, 172. See also p. 84, n. 1, supra.
1086 Athenaeus, iv, 36. Cf. Diodorus Siculus, v, 28, §§ 4-5 and
Strabo, iv, 4, § 3.
1087 Proc. Soc. Ant., 2nd ser., iv, 1867-70, pp. 164-70; Journ.
Brit. Archaeol. Association, xxxvi, 1880, pp. 254-61; J.
Anderson, Scotland in Pagan Times,—the Iron Age, p.
207; R. Munro, Prehist. Scotland, pp. 348-9; B. C. A.
Windle, Remains of the Prehist. Age, p. 266; Proc. Soc.
Ant. Scot., xxxviii, 1904, pp. 541-7. It must be admitted
that conclusive evidence is wanting to prove that any of
the Cornish subterranean dwellings were inhabited before
the Roman occupation (see Vict. Hist. of ... Cornwall, i,
367-9). The ‘hut-clusters’ of Cornwall, of which Chrysoister
is a good example (W. C. Lukis, Prehist. Stone Monuments
of the Brit. Isles,—Cornwall, p. 19) were probably later
than the hut-circles of the same county. Some may have
been built before the Christian era, but they were certainly
inhabited in Roman times (Vict. Hist. of ... Cornwall, i,
370).
1089 Proc. Soc. Ant. Scot., xxxv, 1901, pp. 116-7, 119, 147;
xxxviii, 1904, p. 558.
1090 Proc. Soc. Ant. Scot., xxxv, 1901, pp. 146-8; Guide to the
Ant. of the Bronze Age (Brit. Museum), pp. 35-6; A. Lang,
The Clyde Mystery, p. 41.
1091 Journ. Anthr. Inst., xv, 1886, pp. 463-5; xxviii, 1899, pp.
150-4; R. Munro, The Lake-Dwellings of Europe, pp. 454,
459, 461, 475, 493. Dr. Munro (ib., pp. 490-2) observes
that ‘in the early centuries of the Christian era the
distribution of crannogs in Scotland and Ireland closely
coincides with a well-defined area in which the Celtic
language was spoken’, though he admits that ‘they have
not been found in the south-eastern provinces of
Scotland’. ‘In this wider area’ [including Southern Britain],
he continues, ‘on the supposition that the Celts were the
introducers or founders of the system, we ought to find
some vestiges of these dwellings.... This is precisely what
the general researches into British lake-dwellings have
shown in the stray remnants of them that have been
found in Llangorse, Holderness, the meres of Norfolk and
Suffolk, Cold Ash Common, etc. All these, with perhaps
the exception of the pile-structures at London Wall,
appear to be older than the majority of the crannogs of
Scotland and Ireland.... Taking all these facts into account
... I am inclined to believe that we have here evidence of
a widely distributed custom which underlies the
subsequent [to Caesar] great development which the
lake-dwellings assumed in Scotland and Ireland. Moreover,
I believe it probable that the early Celts had got this
knowledge from contact with the inhabitants of the pile-
dwellings of Central Europe.’
Llangorse is the only Welsh site at which a lake-dwelling
has been found (ib., p. 464). I venture to ask the doctor
why lake-dwellings are so rare in England and Wales,
where, on his theory, they ought to abound; why the
Scottish and Irish Celts did not apply their ‘knowledge’ for
some centuries after they reached the British Isles; and
why lake-dwellings are non-existent (ib., p. 493) in Spain
and Portugal, where Celts were numerous (G. Dottin,
Manuel pour servir à l’étude de l’ant. celt., pp. 324, 329-
31, 349)? And, seeing that there are pile-dwellings in New
Guinea and Central Africa, is it not conceivable that those
of the British Isles had no connexion with Central Europe?
1092 Cf. Tacitus, Germania, 24, and Archaeologia, xliii, 1871, pp.
439-40.
1106 Guide to the Ant. of the Early Iron Age (Brit. Museum), p.
144. Cf. Proc. Soc. Ant., 2nd ser., xviii, 1901, p. 373.
1107 Vict. Hist. of ... Lancs, i, 246. Only one has come to light in
Durham (Vict. Hist. of ... Durham, i. 209).
1119 See Rev. arch., 3e sér., xli, 1902, p. 428, and my Caesar’s
Conquest of Gaul, 1903, p. 12, n. 1.
1132 See Rev. celt., ii, 1873-5, p. 1; iv, 1879-80, pp. 57-8; xviii,
1897, p. 259; E. B. Tylor, Prim. Culture, ii, 1903, pp. 221,
228.
1134 M. Jullian (Rev. des études anc., iv, 1902, p. 101) points
out that the texts fall into two groups, one of which, all
posterior to 100 B.C., deals with the Transalpine Celts, and
the other, mostly earlier, with all the others, except the
Britons.
1135 Rev. celt., xii, 1891, p. 316; Rev. num., 3e sér., ii, 1884, pp.
179-202; Rev. des études anc., iv, 1902, p. 279, n. 2.
1137 J. Rhys, Celtic Heathendom, p. 235. See also Rev. celt., iv,
1879-80, p. 45; x, 1889, pp. 485, 487, 489; H. Gaidoz,
Esquisse de la rel. des Gaulois, 1879, p. 11, Études de
mythologie gaul.,—Le dieu gaul. du soleil, 1886, pp. 90-1,
93; Rev. num., 3e sér., ii, 1884, p. 201, n. 1; Archaeol.
Review, ii, 1889, p. 124; Journ. Brit. Archaeol. Association,
1, 1894, pp. 105-9; and G. Dottin, La rel. des Celtes, pp.
5-16, 56-7, 60.
1138 Caesar does not say that Mercury was actually the
supreme deity of the Gauls, but only the most fervently
worshipped: he expressly says that they regarded their
Jupiter as the lord of the celestials. ‘It must not be
supposed,’ says Sir Alfred Lyall (Asiatic Studies, i, 1899, p.
121), ‘that even the uppermost gods of Hinduism have
retired behind mere ceremonial altars, like constitutional
monarchs.... But there seem to be many grades of
accessibility among them, from Brahma—who, since he
created the world, has taken no further trouble about it,
and is naturally rewarded by possessing only one or two
of the million temples to Hindu gods,’ &c.
1143 See Rev. des études anc., vi, 1904, p. 329. Cf. Sir A. Lyall,
Asiatic Studies, i, 1899, pp. 2-3, 6.
1145 See pp. 273 n. 7, 284, infra, and G. Boissier, La rel. des
Romains, i, 1892, pp. 335, 340-1.
1146 Folk-Lore, xvii, 1906, pp. 32, 324. See Mr. A. B. Cook’s
series of articles in the same volume and in the first
number of vol. xviii.
1153 M. Camille Jullian (Rev. des études anc., iv, 1902, p. 109,
n. 1) points out that in vol. vii [p. 331] of the Corpus inscr.
Lat. there are sixty-one inscriptions in honour of Mars [of
which, however, eight are uncertain], and only eight in
honour of Mercury; and the greater popularity of Mars is
also apparent in the supplements published in Ephemeris
epigraphica (iii, 1877, pp. 125, 128; iv, 1881, p. 196; vii,
1892, pp. 289, 299, 313, 324, 332, 334, 352). But no
account should be taken of those inscriptions in which the
name of Mars is not coupled with that of a Celtic deity,
though even with this reservation the ascendancy of Mars
remains unaffected.
1154 See Rev. des études anc., iv, 1902, p. 109, n. 1. Even in
Gaul the cult of Mars appears to have preponderated
among the Aquitani (ib., pp. 106-7, and Corpus inscr. Lat.,
xiii, 87, 108-17, 209-13).
1155 B. G., vi, 17, §§ 3-5. Cf. J. Rhys, Celtic Heathendom, pp.
49-50.
1167 Corpus inscr. Lat., vii, 200, 203, 875, 1062. Cf. W. H.
Roscher, Lex. der griech. und röm. Myth., i, 1884-6, col.
819, and H. d’A. de Jubainville, Les Celtes, p. 35.
1168 Ib., p. 33. Cf. J. Rhys, Celtic Inscr. in France and Italy, p.
11.
1178 Rev. celt., xvii, 1896, pp. 45-59. Cf. G. Dottin, La rel. des
Celtes, pp. 21-2. The Celtic name of the god on the altar
at Sarrebourg was Sucellos.
1182 Germ., 9.
1183 Rev. des études anc., iv, 1902, p. 228; v, 1903, p. 106.
1185 Class. Rev., xviii, 1904, pp. 361, 367-72, 375; Folk-Lore,
xv, 1904, p. 264; xvi, 1905, p. 321; xvii, 1906, p. 30.
1193 Corpus inscr. Lat., vii, 168a, 221, 348, 559; Ephemeris
epigr., iii, 1877, p. 120; iv, 1881, p. 198a; Rev. des études
anc., viii, 1906, pp. 53-8.
1194 Rev. celt., i, 1870-2, pp. 306-19.
1198 Diodorus Siculus, v, 29, § 4; Rev. celt., viii, 1887, pp. 47,
59, n. 13; H. d’A. de Jubainville, La civilisation des Celtes,
pp. 374-5; Rev. des études anc., v, 1903, p. 252.
1202 Corpus inscr. Lat., xiii, 3026 b, c. Cf. G. Dottin, La rel. des
Celtes, pp. 20-1, 28, and Rev. celt., xxvi, 1905, p. 199. M.
d’Arbois de Jubainville (ib., p. 195) thinks that the original
Epona was the mare deified, and that the woman in the
statues was a Greek addition. Cf. A. Lang, Custom and
Myth, 1885, pp. 118-20, and Sir A. Lyall’s Asiatic Studies,
i, 1899, p. 18.
1205 B. G., vi, 13, § 10, 17, § 5; Tac., Ann., xiv, 30; Dion
Cassius, lxii, 7, § 3. Cf. G. Dottin, La rel. des Celtes, p. 30.
Strabo (iv, 4, § 6), Diodorus Siculus (v, 27, § 4), Plutarch
(Caesar, 26), and Suetonius (Divus Iulius, 54) speak of
temples in Transalpine Gaul; but all archaeologists would
admit that the words which they used—τέμενος, ἱερόν,
fanum, and templum—did not denote roofed edifices. I
think, however, that Livy (xxii, 57, § 10, xxiii, 24, § 11)
had such buildings in mind. Whether he was well informed
is another question. Cf. Rev. des études anc., iv, 1902, pp.
279-80.
1208 Rev. celt., xiii, 1892, pp. 190-3. Cf. vol. xi, 1890, p. 225. M.
d’A. de Jubainville (Rev. arch., 4e sér., viii, 1906, p. 146)
says that ‘la vie de Saint Samson désigne par le mot
simulacrum une pierre levée, lapis stans, qui était l’objet
d’un culte en Grande-Bretagne au milieu du vie siècle’, &c.
1210 M. Jullian (Rev. des études anc., iv, 1902, pp. 284 n. 6,
285 n. 1), referring to the passage in which Lucan (iii,
412-3) describes the Druids’ grove near Massilia,—
1214 Germ., 9.
1215 G. Boissier, La rel. rom., 1892, pp. 8, 35. Cf. Ovid, Fasti, vi,
295.
1216 See Guide to the Ant. of the Early Iron Age (Brit.
Museum), p. 115.
1221 Guide to the Ant. of the Early Iron Age (Brit. Museum), pp.
106-7, 110-1. Cf. Crania Britannica, ii, pl. 6 and 7, p. 6. Mr.
Reginald Smith (Guide, &c., p. 112) remarks, in regard to
the ‘Danes’ Graves’ near Driffield, in the East Riding of
Yorkshire, that ‘the bodies lay indifferently on the right or
left side, though the majority had the head at the north
end of the grave: there was thus’, he adds, ‘no tendency
to face the sun, as in the Bronze period’. Since the bodies,
on whichever side they lay, would have faced either the
morning or the afternoon sun, Mr. Smith’s observation
apparently assumes that in the Bronze period corpses
were laid so as to face the morning sun, which was far
from being an invariable rule. See pp. 188-9, supra, and
the authorities there cited; also Wilts Archaeol. and Nat.
Hist. Mag., x, 1866, p. 101. Unhappily Sir R. C. Hoare,
from whom we learn that in Wiltshire corpses were
generally laid with their heads pointing northward, omits
to say whether they were laid on the right or the left side.
[See Addenda.]
1222 J. Romilly Allen, Celtic Art, pp. 63-71; Guide to the Ant. of
the Early Iron Age (Brit. Museum), pp. 104-20.
1227 Archaeologia, lii, 1890, pp. 324-7. Cf. Guide to the Ant. of
the Early Iron Age (Brit. Museum), pp. 82-3, and see also
W. C. Borlase, Nenia Cornubiae, pp. 247-51.
1236 See Rev. des études anc., vi, 1904, pp. 47-8, 53, 55, 59-
60.
1239 Professor Rhys virtually admits this when he says that the
Brythonic dialect was largely influenced by the language
of the aborigines. See p. 452, n. 8, infra.
ebookmasss.com