<jupyter_start><jupyter_text>Amazon Review Sentiment AnalysisThe purpose of this exercise is to determine whether sentiment of Amazon reviews can be determined from features comprised solely of words from the review text. Then the transferability of the predictions needs to be tested on other categories of Amazon reviews<jupyter_code>import numpy as np 
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import gzip
import requests
import os.path

from sklearn.metrics import confusion_matrix, roc_auc_score, make_scorer
from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV
from sklearn.naive_bayes import BernoulliNB
from sklearn.ensemble import GradientBoostingClassifier, RandomForestClassifier
from sklearn.feature_extraction.text import CountVectorizer

%matplotlib inline
url = 'https://s3.amazonaws.com/amazon-reviews-pds/tsv/amazon_reviews_us_Home_v1_00.tsv.gz'
fn = 'ahome_reviews.csv'
if not os.path.isfile(fn):
    r = requests.get(url, stream=True)
    with open('ahome_reviews.csv', 'wb') as handle:
        for block in r.iter_content(chunk_size=1024):
            handle.write(block)
home_df = pd.read_csv(gzip.open('ahome_reviews.csv'), delimiter='\t', nrows=10000,error_bad_lines=False)
home_df = home_df.loc[:, ['star_rating', 'review_body']]
home_df.head()
home_df.isna().sum()
home_df.dropna(how='any', axis=0, inplace=True)
positive_words = ['good', 'better', 'best', 'great', 'greatest', 'excellent', 'amazing', 'awesome', 'incredible', 'nice']

for word in positive_words:
    home_df[word] = home_df['review_body'].apply(lambda x: 1 if word in x.lower() else 0)
home_df['sentiment'] = home_df['star_rating'].apply(lambda x: 1 if x>3 else 0)
home_df.describe()
X = home_df.iloc[:, 2:-1]
Y = home_df.iloc[:, -1]
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, random_state=1337)
bnb = BernoulliNB()
bnb.fit(X_train, Y_train)
bnb.score(X_test, Y_test)
 cross_val_score(bnb, X, Y, cv=8)
pred = bnb.predict(X_test)
confusion_matrix(Y_test, pred)
clf = GradientBoostingClassifier(loss='exponential', learning_rate=0.5, n_estimators=500, subsample=0.9)
clf.fit(X_train, Y_train)
clf.score(X_train, Y_train)
gb_pred = clf.predict(X_test)
confusion_matrix(Y_test, gb_pred)
def balanced_ttsplit(X, Y, test_split=0.25):
    '''A function that takes in data frames or arrays with features and targets
    and returns balanced training and test splits for those features and targets'''
    # Determine number of classes
    target_values = np.unique(Y)
    
    # Create a dictionary linking the classes to their indices
    indices = {}
    for value in target_values:
        indices[value] = np.where(Y==value)
        
    # Determine the smallest class and determine n_test/train based on that class
    min_length = min([len(v[0]) for k,v in indices.items()])
    
    n_test = int(test_split * min_length)
    n_train = int(min_length - n_test)
    
    X_train, X_test = pd.DataFrame(), pd.DataFrame()
    Y_train, Y_test = pd.DataFrame(), pd.DataFrame()
    
    for value in target_values:
        # Randomly select indices for test and train sets
        test_indices = np.random.choice(indices[value][0], size=n_test, replace=False)
        train_choices = [e for e in indices[value][0] if e not in test_indices]
        train_indices = np.random.choice(train_choices, size=n_train, replace=False)
        
        # Append randomly selected features to the feature sets
        X_train = pd.concat([X_train, X.iloc[train_indices]])
        X_test = pd.concat([X_test, X.iloc[test_indices]])
        
        # Append randomly selected targets to the target sets
        Y_train = pd.concat([Y_train, Y.iloc[train_indices]])
        Y_test = pd.concat([Y_test, Y.iloc[test_indices]])
       
        
    return X_train, X_test, Y_train, Y_test
  
X_train, X_test, Y_train, Y_test = balanced_ttsplit(X, Y)
bnb = BernoulliNB()
bnb.fit(X_train, Y_train)
bnb.score(X_test, Y_test)
pred = bnb.predict(X_test)
confusion_matrix(Y_test, pred)
clf = GradientBoostingClassifier(n_estimators=250)
clf.fit(X_train, Y_train)
clf.score(X_train, Y_train)
gb_pred = clf.predict(X_test)
confusion_matrix(Y_test, gb_pred)
pos_df = home_df[['star_rating', 'review_body', 'sentiment']].iloc[list(np.where(home_df['sentiment']==1))[0], :]
neg_df = home_df[['star_rating', 'review_body', 'sentiment']].iloc[list(np.where(home_df['sentiment']==0))[0], :]
vect = CountVectorizer(max_df=0.9, min_df=0.02)
vect.fit_transform(home_df['review_body'])
print(vect.get_feature_names())
stpwrds = ['34', 'about', 'after', 'again', 'all', 'also', 'am', 'an', 'and', 'another', 'any', 'are', 'arrived', 'as',
           'at', 'back', 'be', 'because', 'bed', 'been', 'before', 'bit', 'bought', 'br',
           'but', 'buy', 'by', 'came', 'can', 'color', 'colors', 'could', 'definitely', 'did', 'didn',
           'do', 'does', 'doesn', 'don', 'easily', 'enough', 'even', 'every', 'exactly', 'expected',
           'far', 'few', 'first', 'fit', 'for', 'from', 'get', 'got', 'had', 'has',
           'have', 'how', 'if', 'in', 'into', 'is', 'it', 'item', 'its', 'just', 'keep', 'light', 'like', 'little',
           'long', 'look', 'looking', 'looks', 'lot', 'made', 'make', 'me', 'more', 'much', 'my',
           'need', 'needed', 'new', 'no', 'not', 'now', 'of', 'off', 'on', 'one', 'only', 'or', 'ordered',
           'other', 'our', 'out', 'over', 'pillow', 'price', 'product', 'purchase',
           'purchased', 'put', 'really', 'received', 'recommend', 'room', 'see', 'set', 'sheets',
           'size', 'small', 'so', 'some', 'still', 'sturdy', 'than', 'that', 'the', 'them', 'then',
           'there', 'these', 'they', 'thing', 'this', 'time', 'to', 'too', 'two', 'up', 'use', 'used', 'using', 've', 
           'very', 'wanted', 'was', 'way', 'we', 'well', 'were', 'what', 'when', 'which', 'will', 'with', 'would', 'you', 
           'your']
vect = CountVectorizer(max_df=0.9, min_df=0.02, stop_words=stpwrds)
vect.fit_transform(pos_df['review_body'])
pos_words = vect.get_feature_names()
vect = CountVectorizer(max_df=0.9, min_df=0.02, stop_words=stpwrds)
vect.fit_transform(neg_df['review_body'])
neg_words = vect.get_feature_names()
negative_words = [w for w in neg_words if w not in pos_words]
pos_words = [w for w in pos_words if w not in neg_words]
new_df = home_df[['star_rating', 'review_body', 'sentiment']]
for word in pos_words:
    new_df[word] = new_df['review_body'].apply(lambda x: 1 if word in x.lower() else 0)
for word in negative_words:
    new_df[word] = new_df['review_body'].apply(lambda x: -1 if word in x.lower() else 0)
X = new_df.iloc[:, 3:]
Y = new_df.iloc[:, 2]

X_train, X_test, Y_train, Y_test = balanced_ttsplit(X, Y)

bnb = BernoulliNB()
bnb.fit(X_train, Y_train)
bnb.score(X_test, Y_test)
pred = bnb.predict(X_test)
confusion_matrix(Y_test, pred)
clf = GradientBoostingClassifier(n_estimators=250)
clf.fit(X_train, Y_train)
clf.score(X_train, Y_train)
gb_pred = clf.predict(X_test)
confusion_matrix(Y_test, gb_pred)
'''roc_auc = make_scorer(roc_auc_score)

param_dict = {'n_estimators': [100, 250, 500], 'learning_rate': [0.0001, 0.001, 0.01, 0.1, 0.25],
              'max_depth': [2, 3, 4, None], 'loss': ['deviance', 'exponential'], 
              'subsample': [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]}

gscv = GridSearchCV(clf, param_dict, scoring=roc_auc, iid=False, cv=6)
gscv.fit(X, Y)
gscv.score(X, Y)
gscv.best_params_
gscv_pred = gscv.predict(X_test)
confusion_matrix(Y_test, gscv_pred)'''
#grid_score_df = pd.DataFrame(gscv.cv_results_)
#grid_score_df.head()
'''pd.options.display.max_columns=None
grid_score_df = grid_score_df.sort_values('rank_test_score')
grid_score_df.to_csv('amazon_reviews_gscv_params.csv')'''
rfc = RandomForestClassifier()

param_dict = {'n_estimators': [50, 100, 500],
              'max_depth': [2, 3, None], 'criterion': ['gini', 'entropy']}

gscv = GridSearchCV(rfc, param_dict, scoring='accuracy', iid=False, cv=6)
gscv.fit(X_train, Y_train)
gscv.score(X_train, Y_train)
gscv_pred = gscv.predict(X_test)
confusion_matrix(Y_test, gscv_pred)
from sklearn.linear_model import LogisticRegression

lr = LogisticRegression(C=1, penalty='l2', solver='liblinear', max_iter=1000)

# Fit the model.
fit = lr.fit(X_train, Y_train)

# Display.
print('Coefficients')
print(fit.coef_)
print(fit.intercept_)
pred_lr = lr.predict(X_test)

print('\n Percentage accuracy')
print(lr.score(X_train, Y_train))
confusion_matrix(Y_test, pred_lr)
lr = LogisticRegression(C=10, penalty='l1', solver='liblinear', max_iter=1000)

# Fit the model.
fit = lr.fit(X_train, Y_train)

# Display.
print('Coefficients')
print(fit.coef_)
print(fit.intercept_)
pred_lr = lr.predict(X_test)

print('\n Percentage accuracy')
print(lr.score(X_train, Y_train))
confusion_matrix(Y_test, pred_lr)
url = 'https://s3.amazonaws.com/amazon-reviews-pds/tsv/amazon_reviews_us_Health_Personal_Care_v1_00.tsv.gz'
fn = 'ahealth_reviews.csv'
if not os.path.isfile(fn):
    r = requests.get(url, stream=True)
    with open('ahealth_reviews.csv', 'wb') as handle:
        for block in r.iter_content(chunk_size=1024):
            handle.write(block)
health_df = pd.read_csv(gzip.open('ahealth_reviews.csv'), delimiter='\t', nrows=5000)
health_df = health_df.loc[:, ['star_rating', 'review_body']]
health_df.dropna(how='any', axis=0, inplace=True)

for word in pos_words:
    health_df[word] = health_df['review_body'].apply(lambda x: 1 if word in x.lower() else 0)
for word in negative_words:
    health_df[word] = health_df['review_body'].apply(lambda x: -1 if word in x.lower() else 0)
    
health_df['sentiment'] = health_df['star_rating'].apply(lambda x: 1 if x>3 else 0)

X = health_df.iloc[:, 2:-1]
Y = health_df.iloc[:, -1]
models = [bnb, clf, gscv, lr]
for model in models:
    pred = model.predict(X)
    print('Accuracy for {} model: {}'.format(str(model).split('(')[0], model.score(X,Y)))
max_class = max(len(np.where(Y==1)[0]), len(np.where(Y==0)[0]))
print('Null Accuracy: {:2f}'.format(max_class/len(Y)))
url = 'https://s3.amazonaws.com/amazon-reviews-pds/tsv/amazon_reviews_us_Digital_Ebook_Purchase_v1_00.tsv.gz'
fn = 'aebook_reviews.csv'
if not os.path.isfile(fn):
    r = requests.get(url, stream=True)
    with open('aebook_reviews.csv', 'wb') as handle:
        for block in r.iter_content(chunk_size=1024):
            handle.write(block)
ebook_df = pd.read_csv(gzip.open('aebook_reviews.csv'), delimiter='\t', nrows=5000)
ebook_df = ebook_df.loc[:, ['star_rating', 'review_body']]
ebook_df.dropna(how='any', axis=0, inplace=True)

for word in pos_words:
    ebook_df[word] = ebook_df['review_body'].apply(lambda x: 1 if word in x.lower() else 0)
for word in negative_words:
    ebook_df[word] = ebook_df['review_body'].apply(lambda x: -1 if word in x.lower() else 0)
    
ebook_df['sentiment'] = ebook_df['star_rating'].apply(lambda x: 1 if x>3 else 0)

X = ebook_df.iloc[:, 2:-1]
Y = ebook_df.iloc[:, -1]
models = [bnb, clf, gscv, lr]
for model in models:
    pred = model.predict(X)
    print('Accuracy for {} model: {}'.format(str(model).split('(')[0], model.score(X,Y)))
max_class = max(len(np.where(Y==1)[0]), len(np.where(Y==0)[0]))
print('Null Accuracy: {:2f}'.format(max_class/len(Y)))<jupyter_output>Null Accuracy: 0.848000
{'fraction_non_alphanumeric': 0.16702241195304163, 'fraction_numerical': 0.018676627534685165, 'mean_word_length': 4.984566258648218, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 7, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '190467', 'license': 'Apache-2.0', 'n_tokens_mistral': 4436, 'n_tokens_neox': 4287, 'n_words': 961, 'path': 'Amazon Reviews.ipynb', 'repo_name': 'tjeffkessler/thinkful_dsflex', 'size': '11244'}