I’ve opened a kaggle account and used the Best Artworks of All Time dataset to train models to make predictions on art genre based on century and nationality.
Kaggle allows me to load the Jupyter Notebook web app and write python code. Alternatively, the Jupyter Notebook web app is free to download and use on your own computer. See #comments for descriptions of the code.
#import statements
import numpy as np
import pandas as pd
#read dataset on kaggle (first load the dataset when creating the kernel)
df = pd.read_csv('../input/artists.csv')
# convert years to centuries
df.loc[df['years'].str.contains('- 13', na=False), 'years'] = "14th century"
df.loc[df['years'].str.contains('- 14', na=False), 'years'] = "15th century"
df.loc[df['years'].str.contains('- 15', na=False), 'years'] = "16th century"
df.loc[df['years'].str.contains('– 15', na=False), 'years'] = "16th century"
df.loc[df['years'].str.contains('- 16', na=False), 'years'] = "17th century"
df.loc[df['years'].str.contains('- 17', na=False), 'years'] = "18th century"
df.loc[df['years'].str.contains('- 18', na=False), 'years'] = "19th century"
df.loc[df['years'].str.contains('– 18', na=False), 'years'] = "19th century"
df.loc[df['years'].str.contains('- 19', na=False), 'years'] = "20th century" df.loc[df['years'].str.contains('– 19', na=False), 'years'] = "20th century"
df.loc[df['years'].str.contains('- 20', na=False), 'years'] = "21st century"
#Using regex, remove values after first comma in nationality and genre (strings are immutable so assign the reference to the result of string.replace)
df['nationality'] = df['nationality'].astype(str).str.replace(r"[,\/]((\w*)|(.)).*","") df['genre'] =
df['genre'].astype(str).str.replace(r"[,\/]((\w*)|(.)).*","")
#Convert categorical columns to numerical ones
from sklearn.preprocessing import LabelEncoder
var_mod = ['years','genre','nationality']
le = LabelEncoder()
for i in var_mod:
df[i] = le.fit_transform(df[i])
df.dtypes
#Import models from scikit learn module:
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import KFold #For K-fold cross validation
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier, export_graphviz
from sklearn import metrics
#Generic function for making a classification model and accessing performance:
def classification_model(model, data, predictors, outcome):
#Fit the model:
model.fit(data[predictors],data[outcome])
#Make predictions on training set:
predictions = model.predict(data[predictors])
#Print accuracy
accuracy = metrics.accuracy_score(predictions,data[outcome])
print ("Accuracy of predictions1: %s" % "{0:.3%}".format(accuracy))
#Perform k-fold cross-validation with 5 folds
kf = KFold(n_splits=5)
error = []
for train, test in kf.split(data[predictors]):
#Filter training data
train_predictors = (data[predictors].iloc[train,:])
#The target we're using to train the algorithm.
train_target = data[outcome].iloc[train]
# Training the algorithm using the predictors and target.
model.fit(train_predictors, train_target)
#Record error from each cross-validation run
error.append(model.score(data[predictors].iloc[test,:], data[outcome].iloc[test]))
print ("Cross-Validation Score : %s" % "{0:.3%}".format(np.mean(error)))
#Fit the model again so that it can be refered outside the function:
model.fit(data[predictors],data[outcome])
return predictions
#model created by classification_model function uses logistic regression algorithm
outcome_var = 'genre'
model = LogisticRegression()
predictor_var = ['years','nationality']
classification_model(model, df, predictor_var, outcome_var)
#model created by classification_model function uses decision trees algorithm
model = DecisionTreeClassifier()
predictor_var = ['years','nationality']
classification_model(model, df,predictor_var,outcome_var)
#model created by classification_model function uses random forests algorithm
model = RandomForestClassifier(n_estimators=100)
predictor_var = ['years','nationality']
classification_model(model, df,predictor_var,outcome_var)
As expected, each run returns different results. One of the runs returned the following results for the model using logistic regression:
Accuracy of predictions: 26.000%
Cross-Validation Score : 12.000%
array([ 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 10, 7, 7, 7, 7, 7, 6, 7, 6, 6, 7, 10, 7, 6, 6, 1, 6, 6, 7, 6, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 7])
One of the runs returned the following results for the model using decision trees:
Accuracy of predictions: 70.000%
Cross-Validation Score : 32.000%
array([ 5, 5, 13, 7, 19, 19, 15, 2, 12, 20, 10, 5, 5, 19, 1, 7, 16, 13, 1, 10, 15, 10, 7, 14, 6, 1, 6, 1, 7, 10, 7, 1, 6, 7, 15, 7, 16, 20, 7, 15, 7, 15, 5, 9, 19, 0, 7, 6, 6, 0])
One of the runs returned the following results for the model using random forests:
Accuracy of predictions: 70.000%
Cross-Validation Score : 34.000%
array([ 5, 20, 17, 7, 19, 19, 15, 2, 12, 20, 10, 20, 20, 19, 1, 7, 16, 17, 1, 10, 15, 10, 7, 14, 6, 1, 6, 1, 7, 10, 7, 1, 6, 7, 15, 7, 16, 20, 7, 15, 7, 15, 5, 9, 19, 11, 7, 6, 6, 11])
When using LabelEncoder, all of the values in the genre column were converted to numerical values 0-20. Here are the categorical genres represented by each number in the returned numerical array:
0: Abstract Expressionism
1: Baroque
2: Byzantine Art
3: Cubism
4: Early Renaissance
5: Expressionism
6: High Renaissance
7: Impressionism
8: Mannerism
9: Neoplasticism
10: Northern Renaissance
11: Pop Art
12: Post-Impressionism
13: Primitivism
14: Proto Renaissance
15: Realism
16: Romanticism
17: Social Realism
18. Suprematism
19. Surrealism
20. Symbolism