<jupyter_start><jupyter_text>IEMS 308 Lab Session 1  TA: <NAME>  Python Basics   Never used Python? When switching from R to Python, there are two major differences to begin with:1. Indexing: Indexes begin from 0 instead of 1. Python also supports negative indexing, i.e. indexing from the rear.2. Indentation: Demarcates blocks instead of curly brackets { }. For example, nested for loops<jupyter_code>for i in range(10):
    for j in range(3):
        if i<j:
            print("%d < %d" %(i,j))<jupyter_output><empty_output><jupyter_text>There are primarily three data-structures which holds collections of objects: lists, tuples and dictionaries.<jupyter_code># lists are quite similar to the ones in R: can hold different types
l = [1,2.0,3.14e-5,'What?',9.99]  
print(l)

# One useful method - append (to the end)
l.append(34)
l.append([4,5,6])
print("\nList aftter append operations:")
print(l)

# Negative indexing
print(l[-2])
# Tuples are immutable versions of lists - once created can't add or modify
tup1 = (1,2.0,3.14e-5,'What?',9.99)
tup1[3] = 0.4e-4 # returns a TypeError

# Useful as arguments or return values of functions
# Dictionaries are key-value pairs - created by either { } or dict
d = {'list1':l,'tup1':tup1,'color':'orange','temperature':-30}
# No order in which elements are stored

# Adding new key-value pair
d['zzz'] = "sleeping"

# Generators to be used in for loops
d.items() # returns list of key-value pairs
d.keys() # returns list of keys
d.values() # returns list of values

# Example Usage in for loop
for key,value in d.items():
    print((key,value))
# Shorthand for operations - creatings collections on the fly
l2 = [(i,z) for i,z in enumerate(l)]
print(l2)<jupyter_output><empty_output><jupyter_text>Functions Functions in python have the following syntax:```pythondef function_name(arg1,arg2,...,argn):     some operations    return out1,out2,...,outm```**Exercise**: Complete the following function to return the minimum element of a list and its index within the list. Test it on the given list<jupyter_code>def min_list(x):
    '''
    Returns the minimum and its index in the list-like object
    
    Input:
    ---------
    x: list-like object
        
    Output:
    ---------
    min_x: The minimum value in x
    min_index: Index of the minimum value in x
    '''
    
    min_x = x[0]
    min_index = 0
    
    ## Loop through the elements to find the minimum
    #### Your code goes here ######
    
    return min_x, min_index

# Test list
x = [4,9,1,2,2,7,3,5,6,8]
min_list(x)<jupyter_output><empty_output><jupyter_text>Notice the content within the ''' ''' block. This is called the function's docstring and is a convenient way of documenting functions and returning help files for the user. To access the docstring, use either the `python .__doc__` attribute of the function,<jupyter_code>print(min_list.__doc__)<jupyter_output><empty_output><jupyter_text>or use the `help` function.<jupyter_code>help(min_list)<jupyter_output><empty_output><jupyter_text>Docstrings are also used for documenting class methods as show in the next example.  Classes and Objects<jupyter_code># Example of class and object
class Rectangle:  
    def __init__(self, length, height):  
        ''''' 
        We write in here what we need to define the object. 
        Inside the class, we use the defined self-variables as "self.NameOfVariable" 
        '''  
        self.length = length  
        self.height = height  
    def area(self):  # Self-function: Only self-variables required
        ''''' 
        Note that we always have to specify "self" in our class functions
        '''  
        Rec_area=self.length*self.height  
        return Rec_area  
    def horizontal_Concatenation(self, Other_rectangle):  
        '''
        Function that implies the current and another object.  
        It creates a new rectangle by merging the current and another rect
        As it is a Horizontal concatenation we need equal heights 
        Input: 
        ----- 
        self: We always have to specify that 
        Other_rectangle: The other rectangle we want to merge 
         
        Output: 
        ------ 
        New_rectangle: The merged rectangle '''    
        if (self.height != Other_rectangle.height):  
            print('Ups! I cant do that...Different heights!')  
            New_rectangle = 'Err'  
        else:  
            New_rectangle = Rectangle(self.length+Other_rectangle.length, self.height)  
        return New_rectangle  
          
    def vertical_Concatenation(self,Other_rectangle):  
        ''' 
        Function that implies the current and another object. 
        It creates a new rectangle by merging the current and another rect
        As it is a vertical concatenation we need equal lengths 
 
        Input: 
        ----- 
        self: We always have to specify that 
        Other_rectangle: The other rectangle we want to merge 
        
        Output: 
        ------ 
        New_rectangle: The merged rectangle 
        '''          
        if self.length != Other_rectangle.length:  
            print('Agh! I cant do that...Different lengths!')  
            New_rectangle = 'Err'  
        else:  
            New_rectangle = Rectangle(self.length, self.height+Other_rectangle.height)  
        return New_rectangle    


a=Rectangle(2,2)  
b=Rectangle(2,1)  
c = a.vertical_Concatenation(b)  
print(c.area())<jupyter_output><empty_output><jupyter_text>Importing Libraries<jupyter_code># Import libraries
import os
import numpy as np
import matplotlib.pyplot as plt

# import specific submodules/functions
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score 

# needed if using jupyter notebook
%matplotlib inline<jupyter_output><empty_output><jupyter_text>Working directory (Get and set)<jupyter_code># Print current working directory
print(os.getcwd())
# Change working directory
# Path can be relative or absolute 
# Note: Windows users need to use escape sequences for
#       absolute paths
os.chdir(<path>)

# Print new working directory
### YOUR CODE GOES HERE
# Change working directory back to the original one
### YOUR CODE GOES HERE<jupyter_output><empty_output><jupyter_text>NumPy  **Question**: How would you store vectors and matrices using Python built-in types?**Answer**: Lists<jupyter_code># create a vector
a = [1,2,3,4]

# create a Matrix
A = [[1,2,4],[2,4,5],[9,0,1]]<jupyter_output><empty_output><jupyter_text>NumPy (short for Numerical Python) provides an easy and efficient way to deal with vectors, matrices and multi-dimensional arrays.<jupyter_code>import numpy as np
np.__version__<jupyter_output><empty_output><jupyter_text>Creating arrays  From lists<jupyter_code>np.array([1,2,3,4]) # 1D array
# 2-D array
A = np.array([[1,2,4],[2,4,5],[9,0,1]])<jupyter_output><empty_output><jupyter_text>If we want to explicitly set the data type of the resulting array, we can use the `dtype` keyword:<jupyter_code>np.array([1,2,3,4],dtype="float32")<jupyter_output><empty_output><jupyter_text>Generating arrays from scratch<jupyter_code># Initalize 4x6 matrix of ones
np.ones((4,6))
# Integer-vectors of zeros
np.zeros(10,dtype="int")
# First 10 non-negative integers
np.arange(10)
# Sequences of numbers between -1 and 1 spaced by 0.4
np.arange(-1,1,0.4)
# 1d array of uniformly distributed random variables
np.random.seed(1245) # set seed for reproducibility
np.random.rand(3)
# 2d array of standard normal distributed variables
np.random.seed(1245)
np.random.randn(3,5)
# 3d array of integers
np.random.seed(1245)
np.random.randint(10, size=(3, 4, 5))<jupyter_output><empty_output><jupyter_text>**Exercise**: Generate a 1darray (size 6) and 2darray (dimensions 5x4) of uniformly distributed rvs using the randn function. Use seed 678. Denote these arrays by x and x2 respectively.<jupyter_code># Arrays to be used for demonstration
### YOUR CODE GOES HERE<jupyter_output><empty_output><jupyter_text>Array attributes<jupyter_code># Basic array attributes
print("Array ndim: ",x.ndim)
print("Array shape: ",x.shape)
print("Array size: ",x.size)
print("Array dtype: ",x.dtype)
# Basic array attributes
print("Array ndim: ",x2.ndim)
print("Array shape: ",x2.shape)
print("Array size: ",x2.size)
print("Array dtype: ",x2.dtype)<jupyter_output><empty_output><jupyter_text>Array subsetting   Single elements<jupyter_code># Single element - 1d array
# Print the first, last and the element at index 2
# Remember that the index begins at 0
#### YOUR CODE GOES HERE
# Single element - 2d array
# Need two indices
# Print the element in the last row and the last but one column
### YOUR CODE GOES HERE<jupyter_output><empty_output><jupyter_text>Slices and subarrays The syntax for a 1d array is as follows:```pythonx[start:stop:step]```If not provided, the default values are start = 0, stop = size of dimension, step = 1. Note that stop is exclusive, while stary is inclusive.This is similar for multi-dimensional arrays with multiple slices separated by commas. **Exercise**: For the 1d array, do the following:1. subset elements from index 2 to index 4, both included2. subset all elements except the first3. subset all elements except the last4. subset every other element<jupyter_code>### YOUR CODE GOES HERE<jupyter_output><empty_output><jupyter_text>**Exercise**: For the 2d array, do the following:1. subset rows 1 to 3 and columns 1 to 22. assign 1 to all elements of the 3rd column (column 2)3. subset the last but one row<jupyter_code>### YOUR CODE GOES HERE<jupyter_output><empty_output><jupyter_text>Logical subsetting<jupyter_code># subset only non-negative elements
x[x>0]<jupyter_output><empty_output><jupyter_text>Basic math and broadcasting Basic arithmetic operators work on a element-by-element basis. For example:<jupyter_code>np.array([2.,4.,0.5]) * np.array([3,4,5])<jupyter_output><empty_output><jupyter_text>NumPy has a feature called **broadcasting** which allows these operations to performed on arrays with different shapes. Subject to certain constraints, the smaller array is “broadcast” across the larger array so that they have compatible shapes.  **General broadcasting rules:** (from the NumPy documentation)When operating on two arrays, NumPy compares their shapes element-wise. It starts with the trailing dimensions, and works its way forward. Two dimensions are compatible when1. they are equal, or2. one of them is 1If these conditions are not met, a "ValueError: frames are not aligned" exception is thrown, indicating that the arrays have incompatible shapes. The size of the resulting array is the maximum size along each dimension of the input arrays.For a more detailed explanation and examples of compatiable, refer https://docs.scipy.org/doc/numpy-1.15.0/user/basics.broadcasting.html<jupyter_code># Application: centering columns of 2-d array by a 1-d array
np.random.seed(1245)
x = np.random.rand(5,3)

print(x)
print(x+np.array([3,4,5]))<jupyter_output><empty_output><jupyter_text>Common array methods Some examples:| Method call            | Function alternative      | Description                                                 ||------------------------|---------------------------|-------------------------------------------------------------|| x.min()                | np.amin(x)                | Minimum of all elements in array                            || x.sum()                | np.sum(x)                 | Sum of all elements in array                                || x.mean(axis=0)         | np.mean(x,axis=0)         | Mean of elements across axis 0 (if 2d array - column means) || x.sort(axis=1)         | np.sort(x,axis=1)         | Sort array across axis 1 in increasing order                || x.std(axis=0)          | np.std(x,axis=0)          | Standard deviation of elements across axis 0                || x.max(axis=1)          | np.amax(x,axis=1)         | Maximum of elements across axis 1)                          || x.argmax()             | np.argmax(x)              | Returns the indices of the maximum values                   || x.reshape() | np.reshape(x,) | Reshape array according to new shape                        | **Exercise**: Write a function named `normalize` which accepts a 1d or a 2d array and then performs the following operation:- if the input is a 1d array, center it by its mean and then scale by its standard deviation- if the input is a 2d array, center and scale each column by its respective mean and standard deviationThe function should return three arguments: the normalized array (x_normalized), centering factor (loc) and scale factor (scale).<jupyter_code># input arrays to test on
np.random.seed(234)
x = 4 + 2*np.random.randn(10,1)
x2 = np.array([2,5,3]) + np.array([2,1,3])*np.random.rand(10,3)

### YOUR CODE GOES HERE<jupyter_output><empty_output><jupyter_text>Input from files<jupyter_code>import csv
iris_list = []

# You can use the "with open()" syntax for any file - just remember to replace csv.reader
# with the corresponding file parser. We will be using this syntax for saving
# model data in the later labs
with open("../data/iris.csv") as f:
    csv_reader = csv.reader(f,delimiter=',')
    # extract header and array data
    line_count = 0
    for row in csv_reader:
        if line_count == 0:
            col_names = row
        else:
            iris_list.append(row)
        line_count += 1

iris = np.array(iris_list,dtype=float)

print("Column names:")
print(col_names)
print("\nFirst 5 rows:")
print(iris[range(5),:])
        
# Using numpy without returning column names
iris = np.genfromtxt("../data/iris.csv",delimiter=",",names=None,skip_header=1)
print(iris[range(5),:])<jupyter_output><empty_output><jupyter_text>Plots matplotlib is a widely used plotting library. Its submodule pyplot is used for 2d plots.<jupyter_code># uncomment the following lines if you haven't imported pyplot before
# import matplotlib.pyplot as plt
# %matplotlib inline

# Data for scatter plot demonstration
np.random.seed(3456)
x = np.random.randn(100)
y = np.random.randn(100) + 0.01*x
c = 1*(x > 0) + 1*(y>0) # color labels for the points

# Scatter plot
f = plt.figure()
plt.scatter(x,y,c=c);
# Axis labels
plt.xlabel("X-label")
plt.ylabel("Y-label")
plt.show()
# Data for line plot demonstration
x = np.array([0,2,3,4,5,10,15,20,27,40])
y1 = np.exp(-0.3-0.5*x)
y2 = np.exp(-0.5-0.2*x)

# Adjust figure size
plt.rcParams['figure.figsize']  = [6,4]

# Line plot with two different series
f = plt.figure()
plt.plot(x,y1,"-ro",label="Red")
plt.plot(x,y2,"-bo",label="Blue")
# Axis labels
plt.xlabel("X-label")
plt.ylabel("Y-label")
# Legend - loc = 0:best, 1:upperight, 2:upperleft, 3:lowerleft, 4:lowerright, 5:right  
plt.legend(loc = 0)
plt.show()
f.savefig("test.png")<jupyter_output><empty_output><jupyter_text>**Exercise**: Do a scatter plot of the first two columns of the dataset and color code the points using the last column. The first two columns are 'Sepal_length' and 'Sepal_width'.<jupyter_code>### YOUR CODE GOES HERE<jupyter_output><empty_output><jupyter_text>For a more detailed tutorial on pyplot, check https://matplotlib.org/users/pyplot_tutorial.html  Introduction to Scikit-learn models Scikit-learn is a popular machine learning library that has implementations of a large number of common algorithms, including ones for text processing. An advantage of scikit-learn is a consistent syntax across different kinds of models. The models are represented through `Estimator` classes. Estimator classes for machine learning models typically have the following methods:| Method             | Description                                                         ||--------------------|---------------------------------------------------------------------|| .fit(X,y)          | Fits the model on the data. y is not needed for unsupervised models || .predict(X)        | Returns predictions (either values or labels) on the new data       || .predict_proba(X)  | Returns class probabilities on the new data (when applicable)       || .get_params()      | Get the model parameters                                            || .set_params(theta) | Set the model parameters to theta (CAUTION)                         || .score(X,y)        | Returns the prediction score on the new data                        |<jupyter_code># Train logistic regression model on the iris dataset

# uncomment the two import lines if you haven't imported them previously
# from sklearn.linear_model import LogisticRegression
# from sklearn.metrics import accuracy_score

## STEP 1: Subset the predictors and the labels for the iris dataset
## Denote them by X and y respectively
## The labels are the last column in the dataset
### YOUR CODE GOES HERE

## STEP 2: Standardize each of the predictors/features:
## Use the standardize function that your have written in the numpy section
### YOUR CODE GOES HERE

## STEP 3: Create a logistic regression object, fit it to the iris data
# initialize classifier with specific options
clf = LogisticRegression(random_state=5, solver='lbfgs',multi_class='multinomial')
clf.fit(X,y) # fit model to data

## STEP 4: Report the training accuracy score
y_pred = clf.predict(X)
accuracy_score(y,y_pred)<jupyter_output><empty_output><jupyter_text>**Exercise**: Fit a radial-basis support vector machine for classification on the iris dataset. For classification, the estimator class is SVC. Initialize the SVC with arguments `random_state` = 1, `kernel` = 'rbf' and `gamma` = 0.25<jupyter_code># Train SVM on the iris dataset
from sklearn.svm import SVC

### YOUR CODE GOES HERE<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10998864926220205, 'fraction_numerical': 0.01782065834279228, 'mean_word_length': 3.4553729456384326, 'pattern_counts': {'":': 0, '<': 113, '<?xml version=': 0, '>': 114, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '27', 'dir': 'jupyter-structured-clean-dedup', 'id': '614083', 'license': 'MIT', 'n_tokens_mistral': 5483, 'n_tokens_neox': 5176, 'n_words': 1857, 'path': 'Lab1/Lab_session_1.ipynb', 'repo_name': 'syerramilli/iems308_lab', 'size': '17630'}