<jupyter_start><jupyter_text>Python Workshop: Basics I[If you are looking for the **Python, Pycharm & packages installation guide**, [it's here.](https://www.aiismath.com/pages/python_pycharm_installation/python_pycharm_installation/)][![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/YoniChechik/AI_is_Math/blob/master/c_01_intro_to_CV_and_Python/basic_python_tutorial.ipynb) Based on:this [git](https://github.com/zhiyzuo/python-tutorial) of Zhiya Zuo&tutorials from [tutorialspoint](https://www.tutorialspoint.com/python) IntroductionPython is an interpreted, high-level, general-purpose programming language. Created by <NAME> and first released in 1991, Python's design philosophy emphasizes code readability. The language construction and object-oriented approach aims to help programmers write clear, logical code for small and large-scale projects. [Wikipedia]- Python is Interpreted - Python is processed at runtime by the interpreter. You do not need to compile your program before executing it. This is similar to PERL, PHP and MATLAB.- Python is Interactive - You can actually sit at a Python prompt and interact with the interpreter directly to write your programs.- Python is Object-Oriented - Python supports Object-Oriented style or technique of programming that encapsulates code within objects.- Popular Language for Data Analysis - Most of the time, you will need external packages to assist data analyses. ![Python Packages](http://i.imgur.com/Q8trGd1.png) PyCharmPycharm is currently (2019) the most commonly used IDE (Integrated development environment) for programing in python.for complete tutorial on **installation** of Python + Pycharm + additional packages please refer to [this page](https://www.aiismath.com/pages/python_pycharm_installation/python_pycharm_installation/). Jupyter notebookJupyter is an easy way to merge code and explanations in a beautiful way.The easiest way to interact with such notebook (.ipynb) is with [google colab](https://colab.research.google.com). There you can run each cell independently or all cells combined through 'Runtime' section or the play button.the main disadvantage of google colab is that debugging there is problematic. Naming conventionThere are two commonly used style in programming:1. __camelCase__2. __snake_case__ or __lower_case_with_underscore__Always make sure you use one convention consistently across one project.All variable (function and class) names must start with a letter or underscore (_). You can include numbers, but it can't be the first char.<jupyter_code>myStringHere = 'my string'  # valid
x = 3  # valid
x_3 = "xyz"  # valid
# 3_x = "456" # invalid. Numbers cannot be in the first position.<jupyter_output><empty_output><jupyter_text>Lines and indentationPython doesn't need braces to indicate blocks of code for class and function definitions or flow control. Blocks of code are denoted by line indentation (Tabs), which is rigidly enforced.<jupyter_code>if True:
    print("True")
else:
    print("False")<jupyter_output>True<jupyter_text>IndexingIndexing in python start from 0 (like c, unlike Matlab). Accessing a range of list/array is, by convetion, `some_list[start_ind:end_ind_minus_one]`<jupyter_code>x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

y = x[0] #get element 0 
print("y = " + str(y))

y = x[2] #get element 2 
print("y = " + str(y))

y = x[0:2] #get elements 0,1
print("y = " + str(y))

y = x[:2]  # same as [0:2]
print("y = " + str(y))

y = x[3:10]
print("y = " + str(y))

y = x[3:]  # same as above
print("y = " + str(y))<jupyter_output>y = 0
y = 2
y = [0, 1]
y = [0, 1]
y = [3, 4, 5, 6, 7, 8, 9]
y = [3, 4, 5, 6, 7, 8, 9]<jupyter_text>You can also go to last element easily:<jupyter_code>y = x[-1]  # last element
print("y = " + str(y))

y = x[:-1]  # all until the last element - noninclusive
print("y = " + str(y))

y = x[-3:]  # last three elements
print("y = " + str(y))<jupyter_output>y = 9
y = [0, 1, 2, 3, 4, 5, 6, 7, 8]
y = [7, 8, 9]<jupyter_text>Step size is also an option:<jupyter_code>y = x[0:3:2]  # only evens until 3 noninclusive
print("y = " + str(y))

y = x[1:5:2]  # only odds until 5 noninclusive
print("y = " + str(y))

y = x[::3]  # +3 step size - entire list
print("y = " + str(y))

y = x[::-1]  # reverse!
print("y = " + str(y))<jupyter_output>y = [0, 2]
y = [1, 3]
y = [0, 3, 6, 9]
y = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]<jupyter_text>PrimitivesIn this section, we go over some common primitive data types in Python.While the word _primitive_ looks obscure, we can think of it as the most basic data type that cannot be further decomposed into simpler ones. Numbersnumbers without fractional partsare called ___integer___. In Python, they are abbreviated as `int`<jupyter_code>x = 3
type(x)<jupyter_output><empty_output><jupyter_text>numbers with fractional part are floating point numbers. They are named `float` in Python.<jupyter_code>y = 3.0
type(y)<jupyter_output><empty_output><jupyter_text>We can apply arithmetic to these numbers. However, one thing we need to be careful about is ___type conversion___. See the example below.<jupyter_code>z = 2 * x  # int times int
type(z)



z = y ** x  # int to the power float
print(z)
type(z)



z = x / 2  # what will happen when dividing two ints?
z<jupyter_output><empty_output><jupyter_text>BooleanBoolean type comes in handy when we need to check conditions. For example:<jupyter_code>my_error = 1.6
compare_result = my_error < 0.1
print(compare_result)
print(type(compare_result))<jupyter_output>False
<class 'bool'><jupyter_text>There are two valid Boolean values: `True` and `False`. We can also think of them as `1` and `0`, respectively.<jupyter_code>my_error > 0<jupyter_output><empty_output><jupyter_text>When we use Boolean values for arithmetic operations, they will become `1/0` automatically<jupyter_code>(my_error > 0) + 2<jupyter_output><empty_output><jupyter_text>StringsIn Python, we use `str` type for storing letters, words, and any other characters.To initialize a string variable, you can use either double or single quotes.<jupyter_code>my_str1 = "see you"
print(my_str1)
print(type(my_str1))

my_str2 = 'see you later'
print(my_str2)
print(type(my_str2))<jupyter_output>see you
<class 'str'>
see you later
<class 'str'><jupyter_text>We can also use `+` to _concatenate_ different strings<jupyter_code>my_str1 + ' tomorrow'<jupyter_output><empty_output><jupyter_text>One way of formatting strings is equivalent to c language:<jupyter_code>print("1/3 is approximately %.2f" % (1/3))  # %f for floating point number
print(" '%s' != '%s'" % (my_str1, my_str2))  # %s for string<jupyter_output>1/3 is approximately 0.33
 'see you' != 'see you later'<jupyter_text>you can also simply do string concatenation:<jupyter_code>print("Printing a string: " + my_str1 + ", and printing a number: " + str(3))<jupyter_output>Printing a string: see you, and printing a number: 3<jupyter_text>`str` is an **iterable object,** meaning that we can iterate through each individual character:<jupyter_code>print(my_str1[0])
print(my_str1[2:6])<jupyter_output>s
e yo<jupyter_text>Data StructuresIn this section, we discuss some ___nonprimitive___ data structures in Python. ListInitialize a list with brackets. You can store anything in a list, even if they are different types<jupyter_code>a_list = [1, 2, 3]  # commas to separate elements
print("Length of a_list is: %i" % (len(a_list)))
print("The 3rd element of a_list is: %s" %
      (a_list[2]))  # Remember Python starts with 0
print("The last element of a_list is: %s" % (a_list[-1]))  # -1 means the end
print("The sum of a_list is %.2f" % (sum(a_list)))<jupyter_output>Length of a_list is: 3
The 3rd element of a_list is: 3
The last element of a_list is: 3
The sum of a_list is 6.00<jupyter_text>We can put different types in a list<jupyter_code>b_list = [20, True, "good", "good"]
print(b_list)<jupyter_output>[20, True, 'good', 'good']<jupyter_text>Update a list: __pop__, __remove__, __append__, __extend__<jupyter_code>print(a_list)
print("Pop %i out of a_list" % a_list.pop(1))  # pop the value of an index
print(a_list)



print("Remove the string good from b_list:")
b_list.remove("good")  # remove a specific value (the first one in the list)
print(b_list)



a_list.append(10)
print("After appending a new value, a_list is now: %s" % (str(a_list)))<jupyter_output>After appending a new value, a_list is now: [1, 3, 10]<jupyter_text>merge `a_list` and `b_list`:<jupyter_code>a_list.extend(b_list)
print("Merging a_list and b_list: %s" % (str(a_list)))<jupyter_output>Merging a_list and b_list: [1, 3, 10, 20, True, 'good']<jupyter_text>We can also use `+` to concatenate two lists<jupyter_code>a_list + b_list<jupyter_output><empty_output><jupyter_text>TupleTuple is a special case of list whose elements cannot be changed (immutable).Initialize a tuple with parenthesis:<jupyter_code>a_tuple = (1, 2, 3, 10)
print(a_tuple)
print("First element of a_tuple: %i" % a_tuple[0])<jupyter_output>(1, 2, 3, 10)
First element of a_tuple: 1<jupyter_text>You can't change the values of a tuple:<jupyter_code># a_tuple[0] = 5<jupyter_output><empty_output><jupyter_text>In order to create a single value tuple, you need to add a ','<jupyter_code>a_tuple = (1)  # this would create a int type
print(type(a_tuple))
b_tuple = (1,)  # this would create a tuple type, take note of the comma.
print(type(b_tuple))<jupyter_output><class 'int'>
<class 'tuple'><jupyter_text>Dictionary Dictionary: key-value pairsInitialize a dict by curly brackets `{}`<jupyter_code>d = {}  # empty dictionary
# add a key-value by using bracket (key). You can put anything in key/value.
d[1] = "1 value"
print(d)



# Use for loop to add values
for index in range(2, 10):
    d[index] = "%i value" % index
print(d)
print("All the keys: " + str(d.keys()))
print("All the values: " + str(d.values()))



for key in d:
    print("Key is: %i, Value is : %s" % (key, d[key]))<jupyter_output>Key is: 1, Value is : 1 value
Key is: 2, Value is : 2 value
Key is: 3, Value is : 3 value
Key is: 4, Value is : 4 value
Key is: 5, Value is : 5 value
Key is: 6, Value is : 6 value
Key is: 7, Value is : 7 value
Key is: 8, Value is : 8 value
Key is: 9, Value is : 9 value<jupyter_text>Side note: mutable Vs. immutable objects**Everything in Python is an object**, and object can be either mutable (changeable after creation) or immutable.Almost all Python objects are mutable, except from the primitives (numbers, booleans, strings) and tuplesWhy it's interesting? because when you reference a new variable, it's always soft link (like a shortcut in windows), and if you change a mutable object, it reference changes too! Something that can cause big bugs!<jupyter_code># mutable object: no problem
a = 'Hello'
b = a
b = b + ' World!'
print(a)
print(b)



# immutable object: big problem
a = ['Hello']
b = a
b[0] = 'World!'
print(a)
print(b)



# use .copy() to overcome this:

c = a.copy()
c[0] = "other world"
print(a)
print(c)<jupyter_output>['World!']
['other world']
{'fraction_non_alphanumeric': 0.11643711489670171, 'fraction_numerical': 0.020659659296846683, 'mean_word_length': 5.242647058823529, 'pattern_counts': {'":': 0, '<': 95, '<?xml version=': 0, '>': 96, 'https://': 7, 'lorem ipsum': 0, 'www.': 3, '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': '26', 'dir': 'jupyter-structured-clean-dedup', 'id': '93042', 'license': 'MIT', 'n_tokens_mistral': 4000, 'n_tokens_neox': 3762, 'n_words': 1344, 'path': 'c_01_intro_to_CV_and_Python/basic_python_tutorial.ipynb', 'repo_name': 'keissar3/AI_is_Math', 'size': '11046'}