---
# System prepended metadata

title: Python Data Science Toolbox (Part 1)(Datacamp)
tags: [scope, Datacamp, lambda functions, error-handling, python, def function]

---

{%hackmd @88u1wNUtQpyVz9FsQYeBRg/r1vSYkogS %}
# Python Data Science Toolbox (Part 1)(Datacamp)

> 轉貼修改自[https://hackmd.io/@wh91008/rkVBQY1lS](https://hackmd.io/@wh91008/rkVBQY1lS)

###### tags: `python` `def function` `lambda functions` `error-handling` `scope` `Datacamp`

[TOC]

## First part
### :bulb: 重點語法彙整
- <code class=blue>type()</code>：觀看資料型態 
- <code class=blue>def function()</code>：定義函數
- <code class=blue>return v.s. print()</code>：return與print的差異 
- <code class=blue>keys()</code>：字典
---
### :bulb: 其他觀念彙整

- list與tuple的差異
- 變數可Unpack
---
### :muscle: 重點語法詳述

#### 例題如下

```python=
# Define shout_all with parameters word1 and word2
def shout_all(word1, word2):
    
    # Concatenate word1 with '!!!': shout1
    shout1 = word1 + '!!!'
    
    # Concatenate word2 with '!!!': shout2
    shout2 = word2 + '!!!'
    
    # Construct a tuple with shout1 and shout2: shout_words
    shout_words = (shout1, shout2)

    # Return shout_words
    return shout_words

# Pass 'congratulations' and 'you' to shout_all(): yell1, yell2
yell1, yell2 = shout_all('congratulations', 'you')

# Print yell1 and yell2
print(yell1)
>>> #('congratulations!!!')
print(yell2)
>>> #('you!!!')
```
#### 1. 可使用type()來查看資料型態
```typescript=
以此題來說，yell1="congratulations"為字串型態，則type(yell1)為str
```
#### 2. def function()
:::info
以此題來說，定義了一個function為`shout_all（word1,word2)`，
並且使用這個函數的人必須輸入相對應的`word1`、`word2`，才可使用這個函數。
如程式碼第17列的`shout_all('congratulations', 'you')`，
也就意味著
`word1="congratulations"`
`word2="you"`
而`yell1, yell2 = shout_all('congratulations', 'you')`
則是其他觀念中的"變數可Unpack"
shout_all有兩個變數，被拆開為yell1與yell2
:::

#### 3. return v.s. print()
##### 差異一
- print的作用「輸出數據到控制端」。
- return的作用是「返回計算的值」，結果不能直接打印出來，仍需透過print才能打印。
##### 差異二
- 程序讀到print()，後面的語句仍會被執行
- 程序讀到return，後面的語句不再被執行

- 例題：
```python=
def func(x,y):
    print(x+y)
    return x*y
```
- 從下圖可知：

    令變數f的時候仍然有資訊被打印出來，主要是執行func(x,y)中print(x+y)這列
    ![](https://i.imgur.com/svFLBOx.png)
- 而由下圖可知：
    因為使用到print()，所以印出來的資訊才為return x*y
    ![](https://i.imgur.com/h3EOaPF.png)

#### 4.keys()字典
keys() 函数以列表返回一個字典所有的键。
```python=
dict = {'Name': 'Zara', 'Age': 7}
```
若使用
```python=
dict.keys()
```
則打印出的值為
```python=
dict_keys(['Name', 'Age'])
```

#### 例題: 計算每個類別的數量，並以迴圈存出dict中
```python=
import pandas as pd
df = pd.read_csv('tweets.csv')

col = df['lang']
langs_count = {}
for entry in col:
    if entry in langs_count.keys():
        langs_count[entry] = langs_count[entry] + 1
    else:
        langs_count[entry] = 1
        
print(langs_count)
>>> {'en': 97, 'et': 1, 'und': 2}
```
> def::
```python=
def count_entries(df, col_name):
    """Return a dictionary with counts of 
occurrences as value for each key."""
    langs_count = {}
    col = df[col_name]
    for entry in col:
        if entry in langs_count.keys():
            langs_count[entry] = langs_count[entry] + 1
        else:
            langs_count[entry] = 1 
    
    return langs_count

result = count_entries(tweets_df, 'lang')
print(result)
#{'en': 97, 'et': 1, 'und': 2}
```

###### 更詳細資訊：http://www.runoob.com/python/python-dictionary.html
---
### :muscle: 其他觀念詳述
#### list與tuple的差異
差別主要來自於「tuple的元素值不可修改、刪除」

- List：
:::info
可以儲存數值：list1=[1, 2, 3] 

可以儲存字串：list2=['a', 'p', 'p', 'l', 'e']

可以進行操作：list1+list2 與方法 list.append()相等
:::
 
- Tuple：

:::info
可以儲存數值：tuple1=(1, 2, 3)

可以儲存字串：tuple2=('a', 'p', 'p', 'l', 'e')

可以進行操作：tuple1+tuple2
:::

###### 來源：http://jialin128.pixnet.net/blog/post/159074609-%5Bpython%5D-%E4%B8%B2%E5%88%97%28list%29%E8%88%87%E5%85%83%E7%B5%84%28tuple%29%E6%AF%94%E8%BC%83

- 例如：
:::info
list1=[1,2,3]
若要更改第0個數值為2
則list1[0]=2
print(list1)就會等於[2,2,3]

反之，若tuple1=(1,2,3)
若要將第0個數值更改為2
則只能打
tuple1=(2,2,3)
直接更改變數的值
若打tuple1[0]=2
會出現
TypeError: 'tuple' object does not support item assignment
:::





#### 變數可Unpack

變數除了能併在一起，還能拆開來看，例如：
:::info
nums=(3,4,5)
若寫為
num1,num2,num3=nums
則num1、num2、num3會分別儲存nums對應位子的值
也就是
num1=3
num2=4
num3=5

:::

---
## Second part

### :bulb: 重點語法彙整


- <code class=blue>global與nonlocal</code>：全局變量與局部變量
- <code class=blue>str.upper()</code>：轉換大寫
- <code class=blue>*arg與**kwargs</code>：可變參數
---
### :bulb: 其他觀念彙整

- inner function：相對於First part，此部分的def多了inner function 
- builtins

---
### :muscle: 重點語法詳述

#### global與nonlocal

- local scope
在 function 中宣告
只能用於該 function 中
不同 function 可以使用同名稱的變數

```python=
def square(value):
    """Returns the square of a number."""
    new_val = value ** 2 #local variable
    return new_val

square(3)
#9

new_val
#NameError: name 'new_val' is not defined
```
- global scope
在 function 外宣告
在 function 中使用 global variable 需使用關鍵字 global →該變數在global環境的值會變

```python=
new_val = 10 #global variable
def square(value):
    """Returns the square of a number."""
    new_val = value ** 2 #local variable
    return new_val

square(3)
#9

new_val
#10
new_val = 10 #global variable
def square(value):
    """Returns the square of a number."""
    new_value2 = new_val ** 2 #local variable
    return new_value2

square(3)
#100

new_val = 20
square(3)
#400
new_val = 10 #global variable
def square(value):
    """Returns the square of a number."""
    global new_val
    new_val = new_val ** 2 #local variable
    return new_val

square(3)
#100

new_val
#100
```

```python=
a=0
def global_test():
    global a
    a=3
    return a
print("a =",global_test())

>>> a = 3
```

- nonlocal只可用在嵌套函數
在多重嵌套中，nonlocal只會上溯一層； 而如果上一層沒有，則會繼續上溯。
```python=
def a():
    i = 1
    def b():
        # i = 2
        def c():
            nonlocal i
            i = 3
        c()
        print('b:', i)
    b()
    print('a:', i)
a()
# b: 3
# a: 3
```
###### 資料來源：https://note.qidong.name/2017/07/python-legb/
#### str.upper()
可用來轉換字母為大寫
```python=
str="Hello!how are you?"
str.upper() #轉換大寫 # 反之str.lower()為轉換小寫
# 'HELLO!HOW ARE YOU?''
```


#### *arg與**kwargs
一般函數的參數個數都是固定的，但如果遇到參數數量不固定的狀況，通常會將某些參數填上預設值，在 python function 可以支援兩種可變數量的參數 *args 和 **kwargs。

> *args: 不帶鍵值
```python=
def add_all(*args):
    """Sum all values in *args together."""
    sum_all = 0
    
    for num in args:
        sun_all += num
    
    return sum_all

add_all(5, 10, 15, 20)
# 50
```

>　**kwargs　帶有鍵值(Keyword arguments)
items() 函數以列表返回所有的(鍵, 值) 元組數組。
```python=
def print_all(**kwargs):
    """Print put key-values pairs in **kwargs."""
    for key, value in kwargs.item():
        print(key + ": " + value)
    
print_all(name="dumbledore", job="headmaster")
# name: dumbledore
# jod: hheadmaster
```

```python=
def fun(a, *args, **kwargs):
    print("a={}".format(a))
    for arg in args:
        print('Optional argument: {}'.format( arg ) )

    for k, v in kwargs.items():
        print('Optional kwargs argument key: {} value {}'.format(k, v))

fun(1,22,33, k1=44, k2=55)
# a=1
# Optional argument: 22
# Optional argument: 33
# Optional kwargs argument key: k1 value 44
# Optional kwargs argument key: k2 value 55
```

若是只需要變數的值，就用*arg
若是還需要帶有變數名字的，就用**kwargs
###### 資料來源：http://blog.maxkit.com.tw/2018/12/python-args-kwargs.html

---
### :muscle: 其他觀念詳述

#### inner function
如上述nonlocal之處，此章節多了inner function，即def內還有def
例題：
```python=
# Define echo
def echo(n):
    """Return the inner_echo function."""

    # Define inner_echo
    def inner_echo(word1):
        """Concatenate n copies of word1."""
        echo_word = word1 * n
        return echo_word

    # Return inner_echo
    return inner_echo ###不用多()

# Call echo: twice
twice = echo(2)

# Call echo: thrice
thrice=echo(3)

# Call twice() and thrice() then print
print(twice('hello'), thrice('hello'))
# hellohello hellohellohello
```

#### builtins
該模塊提供對Python的所有“內置”標識符的直接訪問；
例如，builtins.open 是內置函數的全名 open() 。

```python=
import builtins

def open(path):
    f = builtins.open(path, 'r')
    return UpperCaser(f)
```
就是引入了builtins裡面的open函數，另外又多加一些自己的變化
###### 參考資料：https://docs.python.org/zh-cn/3/library/builtins.html



---


## Third part
### :bulb: 重點語法彙整
- <code class=blue>lambda</code>：不需取名的自定義函數 
- <code class=blue>map()</code>
- <code class=blue>list()</code>：轉換資料為list型態 
- <code class=blue>reduce()</code>
- <code class=blue>filter()</code>：篩選
- <code class=blue>try與except</code>：不屬於try情形的就會被歸類於except
- <code class=blue>raise</code>：增加

> filter, map, reduce 都是針對集合物件處理的特殊函式。

---
### :bulb: 其他觀念彙整

- int形式不能用len()

---
### :muscle: 重點語法詳述

#### Lambda functions
> 與def fuction()的意義相近，只差在lambda不需要像def一樣取function名。
> lambda 自訂變數 : 自訂變數要做的事
```python=
raise_to_power = lambda x, y: x ** y
raise_to_power(2, 3)
#8
```
#### Map function
> map(func, seq)
> 定義一個function，接著用這個function來對一個iterable 的物件內每一個元素做處理。主要的用法有三種
需用list()去呼叫結果

```python=
nums = [48, 6, 9, 21, 1]
square_all = map(lambda num: num ** 2, nums)
print(square_all)
#<map object at 0X103e065c0>

print(list(square_all))
#[2304, 36, 81, 441, 1]
```

- 轉換資料型態
```python=
>>> listA = ['1','2','3']
>>> print map(int,listA)
[1, 2, 3]
```
- 搭配自定函式做不同的運算
```python=
>>> def multiple2(x):
... return x*2
...
>>> list1 = [1,3,5,7,9]
>>> print map(multiple2,list1)
[2, 6, 10, 14, 18]
>>> #上與下相同
>>> print [multiple2(x) for x in list1]
[2, 6, 10, 14, 18]
```
- 同時接收多個list做處裡
下面宣告三組list，一個三個參數的函式 adder(x,y,z)，加總後回傳。
```python=
>>> def adder(x,y,z):
... return x+y+z
...
>>> list1 = [1,3,5,7,9]
>>> list2 = [2,4,6,8,10]
>>> list3 = [100,100,100,100,100]
>>>
>>> print map(adder,list1,list2,list3)
[103, 107, 111, 115, 119]
>>>
>>> print [adder(x,y,z) for x,y,z in zip(list1,list2,list3)]
[103, 107, 111, 115, 119]
```
###### 資料來源：http://e8859487.pixnet.net/blog/post/392947555-python-%E5%9F%BA%E7%A4%8E%E7%B3%BB%E5%88%97--map%28%29-%E7%94%A8%E6%B3%95%E8%A7%A3%E8%AA%AA


lambda、map()、list()例題如下：
```python=
# Create a list of strings: spells
spells = ["protego", "accio", "expecto patronum", "legilimens"]

# Use map() to apply a lambda function over spells: shout_spells
shout_spells = map(lambda item:item+'!!!', spells)

# Convert shout_spells to a list: shout_spells_list
shout_spells_list = list(shout_spells) #如果map用在list，就要再打這列，出來才會是list

# Print the result
print(shout_spells_list)
# ['protego!!!', 'accio!!!', 'expecto patronum!!!', 'legilimens!!!']
```
:::info
有個list型態的資料為spells
使用lambda定義一個沒有名字的函數，裡面所有的變數item最後都要+"!!!"
使用map，讓lambda定義的行為，套用到spells中的每個項目
用完map後，資料型態改變了，因此要再使用list()把資料轉回來
最後執行結果
:::



#### list()
可將資料轉為list型態



#### reduce()
> 必須傳入一個binary function(具有兩個參數的函式)，最後僅會回傳單一值。
reduce會依序先取出兩個元素，套入function作用後的回傳值再與List中的下一個元素一同作為參數，以此類推，直到List所有元素都被取完。
```
reduce(function, iterable[, initializer])
```
例題如下：
```python=
from functools import reduce
stark = ['robb', 'sansa', 'arya', 'brandon', 'rickon']
result = reduce(lambda item1, item2: item1 + item2, stark)
print(result)
#robbsansaaryabrandonrickon

def add(x, y) :            # 兩數相加
         return x + y

reduce(add, [1,2,3,4,5])   # 計算列表和：1+2+3+4+5
# 15
reduce(lambda x, y: x+y, [1,2,3,4,5])  # 使用 lambda 匿名函數
# 15
```
#### filter()
用來篩選，例如篩選tweets_df["text"]中每個數值0~2位置的字為"RT"者
```python=
#篩選資料
fellowship = ['frodo', 'samwise', 'merry', 'pippin', 'aragorn', 'boromir', 'legolas', 'gimli', 'gandalf']
result = filter(lambda member: len(member) > 6, fellowship)
result_list = list(result)
print(result_list)
#['samwise', 'aragorn', 'boromir', 'legolas', 'gandalf']
```

```python=
# Select retweets from the Twitter DataFrame: result
result = filter(lambda x:x[0:2]=="RT", tweets_df["text"])

# Create list from filter object result: res_list
res_list= list(result)

# Print all retweets in res_list
for tweet in res_list:
    print(tweet)
```
#### try與except
如果符合try的情況，就會執行某件事；否則全列入except。
例如：
- Error handling with try-except
```python=
# Define shout_echo
def shout_echo(word1, echo=1):
    """Concatenate echo copies of word1 and three
    exclamation marks at the end of the string."""

    # Initialize empty strings: echo_word, shout_words
    echo_word = ''
    shout_words = ''

    # Add exception handling with try-except
    try:
        # Concatenate echo copies of word1 using *: echo_word
        echo_word = echo*word1

        # Concatenate '!!!' to echo_word: shout_words
        shout_words = echo_word + '!!!'
    except:
        # Print error message
        print("word1 must be a string and echo must be an integer.")

    # Return shout_words
    return shout_words

# Call shout_echo
shout_echo("particle", echo="accelerator")
# word1 must be a string and echo must be an integer.
# Out[1]: ''
```
#### raise
可用來增加自定義錯誤訊息
- Error handling by raising an error
```python=
# Define shout_echo
def shout_echo(word1, echo=1):
    """Concatenate echo copies of word1 and three
    exclamation marks at the end of the string."""

    # Raise an error with raise
    if echo<0:
        raise ValueError('echo must be greater than 0')

    # Concatenate echo copies of word1 using *: echo_word
    echo_word = word1 * echo

    # Concatenate '!!!' to echo_word: shout_word
    shout_word = echo_word + '!!!'

    # Return shout_word
    return shout_word

# Call shout_echo
shout_echo("particle", 5)
# 'particleparticleparticleparticleparticle!!!'
```

>　此題第8列處，定義一個如果echo<0，則顯示其為ValueError種類的錯誤訊息
並且讓使用者知道'echo must be greater than 0'

---

### :muscle: 其他觀念詳述
int形式的資料不能使用len()