<jupyter_start><jupyter_text>Python can handle numbers of arbitrary length :)What's actually $2^{2048}$?<jupyter_code>2**2048<jupyter_output><empty_output><jupyter_text>define a function<jupyter_code>def square(x):
    return x * x

print(f"square(10) is {square(10)}")

# or as lambda statement 

qubic = lambda x: x * x * x
print(f"qubic(10) is {qubic(10)}")<jupyter_output>square(10) is 100
qubic(10) is 1000<jupyter_text>loops and formated strings<jupyter_code>for i in range(1,10):
    print(f"square({i}) = {square(i)}")<jupyter_output>square(1) = 1
square(2) = 4
square(3) = 9
square(4) = 16
square(5) = 25
square(6) = 36
square(7) = 49
square(8) = 64
square(9) = 81<jupyter_text>Which numbers appear in both a and b?<jupyter_code>a = [1,2,3,4,5]
b = [4,5,6,7,8]
result = []
for number in a:
    if number in b:
        result.append(number)
        
result<jupyter_output><empty_output><jupyter_text>and more a more compact version with list comprehensions<jupyter_code>[number for number in a if number in b]<jupyter_output><empty_output><jupyter_text>how does this work?<jupyter_code>[i for i in range(1,10)]
[square(i) for i in range(1,10)]
# this will produce the same output

list(map(square,range(1,10)))

# map applies the function (square) to every element of a sequence (numbers 1 to 10)<jupyter_output><empty_output><jupyter_text>and this works for strings too<jupyter_code>[char for char in "hello world"]<jupyter_output><empty_output><jupyter_text>let's plot somethingTo plot a graph, we need to import matplotlib<jupyter_code>%matplotlib inline
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (12, 9)
data = [square(i) for i in range(1,100)]

l = plt.plot(data, 'ro')
plt.show()
cat = ["bored", "happy", "bored", "bored", "happy", "bored"]
dog = ["happy", "happy", "happy", "happy", "bored", "bored"]
activity = ["combing", "drinking", "feeding", "napping", "playing", "washing"]

fig, ax = plt.subplots()
ax.plot(activity, dog, label="dog")
ax.plot(activity, cat, label="cat")
ax.legend()

plt.show()<jupyter_output><empty_output><jupyter_text>Classes and ObjectsPython supports object-oriented programming. Packing your code into classes will help you to keep your code organized, maintainable and it also improves the reusability. You can read about classes in the [Python Docs](https://docs.python.org/3/tutorial/classes.html).Ok, let's define a simple example class for a data loader. Since all deep learning models need data, data loader are very common and you'll find them in various forms.<jupyter_code>class SensorData:
    """A simple class that manages sensor data"""
    
    def __init__(self, url):
        # this is how a constructor in python looks
        self.data_url = url # data url will be a member or class variable
        
    def load_data(self):
        print(f"Todo: load data from {self.data_url}")        

# lets create a instance for our new class
someSensorData = SensorData("http://somewehere-over-the-rainbow.com")
someSensorData.load_data()<jupyter_output>Todo: load data from http://somewehere-over-the-rainbow.com<jupyter_text>If you are familiar with object-oriented programming this should look familiar to you.  Ok, let's add the code to load some dataNow we will extend the class to download some sensor data. The file is CSV formatted and contains a list of temperature, humidity and time values. This is how one line with one data point looks like:```2018-10-03T11:28:35.325Z;23.0;17.0```<jupyter_code>import csv
import urllib

class SensorData:
    """A simple class that loads sensor data"""
    
    def __init__(self, url):
        # this is how a constructor in python looks
        self.data_url = url # dataUrl will be a member or class variable
        
    def load_data(self):
        response = urllib.request.urlopen(self.data_url) # create a http request
        csv_lines = response.read().decode('utf-8').splitlines() # read utf-8 text
        reader = csv.reader(csv_lines, delimiter=';') # read csv
        self.data = [row for row in reader] # convert csv to array
        print(f"{reader.line_num} lines loaded")

# lets create a instance for our new class
temp_hum_data = SensorData("https://www2.htw-dresden.de/~guhr/dist/sensor-data.csv")
temp_hum_data.load_data()<jupyter_output>92547 lines loaded<jupyter_text>We added some code to load the data via http from a webserver. To download the data we imported `urllib.request`, this package handels the http communication for us. Since our data is stored in a csv file, we imported the `csv` package to read the data. Plot the dataNow that we downloaded the data we can plot it. The data property of our class contains a list with our **time** - **temperature** - **humidity** values. And the first entry looks like this:<jupyter_code>temp_hum_data.data[0]
type(temp_hum_data.data[0][0])<jupyter_output><empty_output><jupyter_text>All three values are strings, in order to plot them we need to convert them into time and float values.<jupyter_code>import csv
import urllib
import datetime as dt

class SensorData:
    """A simple class that loads sensor data"""
    
    def __init__(self, url):
        # this is how a constructor in python looks
        self.data_url = url # dataUrl will be a member or class variable
        
    def load_data(self):
        response = urllib.request.urlopen(self.data_url) # create a http request
        csvlines = response.read().decode('utf-8').splitlines() # read utf-8 text
        reader = csv.reader(csvlines, delimiter=';') # read csv
        data = [row for row in reader] # convert csv to array
        self.data = SensorData.parse_data(data) # since parse_data is a static method we call it by using the classname
        print(f"{reader.line_num} lines loaded")
    
    def parse_data(data): # I am a static method
        # this lambda converts a time string into a python datetime object
        parse_time = lambda time_string: dt.datetime.strptime(time_string, "%Y-%m-%dT%H:%M:%S.%fZ")        
        data = [[parse_time(value[0]),float(value[1]),float(value[2])] for value in data]
        return data
        

# lets create a instance for our new class
temp_hum_data = SensorData("https://www2.htw-dresden.de/~guhr/dist/sensor-data.csv")
temp_hum_data.load_data()
temp_hum_data.data[0]<jupyter_output><empty_output><jupyter_text>We converted the data to native python datatypes. Our data is now formatted as native python data types. Now we can plot them:<jupyter_code>import matplotlib.dates as mdates

# take the last 5000 values and slice them
plotdata = temp_hum_data.data[:5000] 
time = [value[0] for value in plotdata]
temp = [value[1] for value in plotdata]
hum = [value[2] for value in plotdata]

fig, ax = plt.subplots()
date_formatter = mdates.DateFormatter('%d %h - %H:%M')
ax.xaxis.set_major_formatter(date_formatter)

ax.plot(time, temp, label="Temperature in °C")
ax.plot(time, hum, label="Humidity in %")
ax.legend()

plt.xticks(rotation=45, ha='right')
plt.xlabel('Time')
plt.title(f'Temperature Graph for the last {len(plotdata)} data points')
plt.show()<jupyter_output><empty_output><jupyter_text>Of course there are ready made packages to load csv files:<jupyter_code>import pandas as pd
data_frame = pd.read_table("https://www2.htw-dresden.de/~guhr/dist/sensor-data.csv", sep = ";", names=["Date", "Temperature", "Humidity"])
data_frame.head()
data_frame[:5000].plot()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11586596689543803, 'fraction_numerical': 0.019512851567756694, 'mean_word_length': 4.55041075429425, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 53, 'https://': 4, 'lorem ipsum': 0, 'www.': 3, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '14', 'dir': 'jupyter-structured-clean-dedup', 'id': '17763', 'license': 'MIT', 'n_tokens_mistral': 2552, 'n_tokens_neox': 2417, 'n_words': 781, 'path': 'hello-python/Short Python Intro.ipynb', 'repo_name': 'oliverguhr/htw-nlp-lecture', 'size': '7431'}