Python將復雜的數據結構隱藏在內置函數中,用C語言來實現,所以只要寫出自己的業務邏輯,Python會自動得出你想要的結果。
內置函數主要有:filter、map、reduce、apply,結合匿名函數lambda、列表解析一起使用,功能更加強大。
如果對于大數據Hadoop和Spark感興趣的話,最好學會這些內置函數的用法。因為Hadoop的分布式計算框架采用的是MapReduce模型,該模型的核心就是Map函數和Reduce函數。
Spark的核心建立在RDD上,RDD的轉換API和動作API也包括filter、map和reduce,并且常與lambda結合使用。
使用內置函數的好處是:
- 使用內置函數,比普通的Python實現,速度要快一倍左右。
- 代碼簡潔。
1 lambda表達式
lambda的主體是一個表達式,而不是一個代碼塊。僅僅能在lambda表達式中封裝有限的邏輯。lambda表達式是起到一個函數速寫的作用,允許在代碼內嵌入一個函數的定義。
如果你不想在程序中對一個函數使用兩次,你也許會想用lambda表達式,它們和普通的函數完全一樣。
原型:
lambda 參數 : 操作(參數)
參數就是函數中所謂的入參,操作就是返回的計算結果,相當于return語句。
在數據分析的過程中,常常需要使用apply和lambda函數。比如:根據逾期天數來給數據打標簽,如果逾期天數大于30天,則為逾期。
data['target'] = data['逾期天數'].apply(lambda x: 1 if x>30 else 0)
例1. 定義一個lambda表達式,求三個數的和。
>>> f=lambda x,y,z:x+y+x
>>> f(1,2,3)
4
>>> f=lambda x,y,z:x+y+z
>>> f(1,2,3)
6
例2. 用lambda表達式求n的階乘。
>>> n=5
>>> reduce(lambda x,y:x*y,range(1,n+1))
120
例3. lambda表達式也可以用在def函數中。
>>> def action(x):
return lambda y:x+y
>>> a=action(2)
>>> a(22)
24
這里定義了一個action函數,返回了一個lambda表達式。其中lambda表達式獲取到了上層def作用域的變量名x的值。
a是action函數的返回值,a(22),即是調用了action返回的lambda表達式。這里也可以把def直接寫成lambda形式。如下:
>>> b=lambda x:lambda y:x+y
>>> a=b(3)
>>> a(2)
5
>>>(b(2))(2)
4
2 filter
>>> help(filter)
Help on built-in function filter in module __builtin__:
filter(...)
filter(function or None, sequence) -> list, tuple, or string
Return those items of sequence for which function(item) is true.
If function is None, return the items that are true. If sequence is a tuple or string,
return the same type, else return a list.
用途:
用于過濾與函數func()不匹配的值, 類似于SQL中select value != 'a'。相當于一個迭代器,調用一個布爾函數func來迭代seq中的每個元素,返回一個是bool_seq返回為True的序列。
filter()把傳入的函數依次作用于每個元素,然后根據返回值是True還是False決定保留還是丟棄該元素。
第一個參數:函數或None。
第二個參數:序列。
說明:
- 如果第一個參數為function,那么返回條件為真的序列(列表,元組或字符串)。
- 如果第一個參數為None的話,那么返回序列中所有為True的項目。
顧名思義,filter過濾列表中的元素,并且返回一個由所有符合要求的元素所構成的列表,符合要求即函數映射到該元素時返回值為True。這里是一個簡短的例子:
number_list = range(-5, 5)
less_than_zero = filter(lambda x: x < 0, number_list)
print(list(less_than_zero))
# 輸出為:
[-5, -4, -3, -2, -1]
這個filter類似于一個for循環,但它是一個內置函數,并且更快。大部分情況下推導式的可讀性更好。
例1. 要過濾掉所有值為False的列表。
print filter(None,[-2,0,2,'',{},()]) # 輸出[-2,2],其余的都為False
例2. 過濾某個字母。
>>> filter(lambda x: x !='a','abcd')
'bcd'
例3. 過濾字母以B開頭的人名。
>>> names = ['Alice','Bob','Smith','David','Barbana']
>>> filter(lambda x: x.startswith('B'),names)
['Bob', 'Barbana']
例4. 過濾fib列表中的奇數,偶數項。
>>> fib = [0,1,1,2,3,5,8,13,21]
>>> filter(lambda x: x%2,fib) # 實際上等同于x%2==1的項才過濾
[1, 1, 3, 5, 13, 21]
>>> filter(lambda x: x%2==0,fib)
[0, 2, 8]
例5. 將2-20間所有質數列出來。
>>> filter(lambda x: not [x for i in range(2,x) if x%i==0],range(2,20))
[2, 3, 5, 7, 11, 13, 17, 19]
例6. 過濾人名為空的序列。
>>> names = ['Alice','Jerry','Sherry','Bob','Tom','']
>>> filter(None,names)
['Alice', 'Jerry', 'Sherry', 'Bob', 'Tom']
例7. 過濾某目錄下所有以test.py結尾的文件。
import os,re # 需要的模塊
files = os.listdir(r'D:\python') # 列出需要查找的目錄的所有文件
test = re.compile('test.py$',re.IGNORECASE) # re.IGNORECASE忽略大小寫
print filter(test.search,files) # 過濾所有滿足條件的文件
>>>
['1test.py', 'test.py']
例8. 過濾所有子列表中,單詞為'Python'的。
def filter_word(word):
try:
return word != 'Python'
except ValueError:
return False
words = [['Perl','Python','Shell'],['Java','C/C++'],['VB','Dephi']]
print [filter(filter_word,word) for word in words] # 用了列表解析的方法
filter的邏輯實現:
def filter(func,seq):
f_seq = [] # 建一個空序列,用于存儲過濾后的元素
for item in seq: # 對序列中的每個元素進行迭代
if func(item): # 如果為真的話
f_seq.append(item) # 滿足條件者,則加入
return f_seq # 返回過濾后的元素
>>> print filter(lambda x: x>0,[-2,0,2]) # 對匿名函數進行過濾,返回正值[2]
3 map
>>> help(map)
Help on built-in function map in module __builtin__:
map(...)
map(function, sequence[, sequence, ...]) -> list
Return a list of the results of applying the function to the items ofthe argument sequence(s).
If more than one sequence is given, the function is called with an argument list consisting
of the corresponding item of each sequence, substituting None for missing values when not all
sequences have the same length. If the function is None, return a list of the items of the
sequence (or a list of tuples if more than one sequence).
用途:
對一個及多個序列執行同一個操作,返回一個列表。
說明:
- 返回一個列表,該列表是參數func對seq1,seq2處理的結果集。
- 可以有多個序列,如果函數為None的話,返回一個序列的列表。
map規范:
map(function_to_apply, list_of_inputs)
大多數時候,我們要把列表中所有元素一個個地傳遞給一個函數,并收集輸出。比方說:
items = [1, 2, 3, 4, 5]
squared = []
for i in items:
squared.append(i**2)
Map可以讓我們用一種簡單而漂亮得多的方式來實現。就是這樣:
items = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, items))
大多數時候,我們使用匿名函數(lambda)來配合map, 所以我在上面也是這么做的。 不僅用于一列表的輸入, 我們甚至可以用于一列表的函數!
def multiply(x):
return (x*x)
def add(x):
return (x+x)
funcs = [multiply, add]
for i in range(5):
value = map(lambda x: x(i), funcs)
print(list(value))
# 輸出為:
[0, 0]
[1, 2]
[4, 4]
[9, 6]
[16, 8]
例1. 常規用法。
>>> map(lambda x: x+1,[1,2,3,4])
[2, 3, 4, 5]
>>> map(lambda x,y: x+y,[1,2,3,4],(10,20,30,40))
[11, 22, 33, 44]
#第一個序列中的第五個元素存在,但在第二個序列中不存在,所以y為False,所以執行5+10
>>> map(lambda x,y: x+y if y else x+10,[1,2,3,4,5],(1,2,3,4))
[2, 4, 6, 8, 15]
>>> map(None,[1,2,3,4,5],(1,2)) #如果是None的話,以None來補齊短序列造成的空缺
[(1, 1), (2, 2), (3, None), (4, None), (5, None)]
>>> names = ['Alice','Jerry','Bob','Barbar']
>>> map(len,names) #求列表中每個元素的長度
[5, 5, 3, 6]
>>> m = [1,4,7]
>>> n = [2,5,8]
>>> map(None,m,n)
[(1, 2), (4, 5), (7, 8)]
>>> import operator #比較兩個列表中元素大小
>>> a = [1,2,3]
>>> b = [0,4,9]
>>> map(operator.gt,a,b)
[True, False, False]
例2. 求0-5之間數,[本身,平方,立方],如:元素2,則返回:[2,4,8]。
def func1(x):
return x # 返回自身
def func2(x):
return x ** 2 # 返回平方
def func3(x):
return x ** 3 # 返回立方
funcs = [func1,func2,func3] # 函數列表
for i in range(5): # 遍歷列表
print map(lambda func: func(i),funcs) # 對其中每個元素執行func1(i),func2(i),func3(i)操作
例3. 實現下面的邏輯結構。
1.0 [1,2,3,4,5]
2.0 [1,2,3,4,5]
....
foos = [1.0,2.0,3.0,4.0,5.0]
bars = [1,2,3,4,5]
def test(foo):
print foo,bars
print map(test,foos)
例4. 結合map和filter,求0-10之間偶數的平方,匯合成列表。
>>> map(lambda x:x**2, filter(lambda x: x%2==0,range(10)))
[0, 4, 16, 36, 64]
map的邏輯實現:
def map(func,seq):
map_seq = [] # 建空序列
for item in seq: # 對序列中每個元素進行處理
map_seq.append(func(item)) # 往空序列中添加func處理過的元素
return map_seq # 返回最后的列表
print map(lambda x: x * 2,[1,2,3,4]) # [2,4,6,8]
4 reduce
>>> help(reduce)
Help on built-in function reduce in module __builtin__:
reduce(...)
reduce(function, sequence[, initial]) -> value
Apply a function of two arguments cumulatively to the items of a sequence, from left to right,
so as to reduce the sequence to a single value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
calculates ((((1+2)+3)+4)+5). If initial is present, it is placed before the items of the sequence
in the calculation, and serves as a default when the sequence is empty.
用途:
func為二元函數,將func作用于seq序列的元素,每次攜帶一對(先前的結果以及下一個序列的元素),連續的將現有的結果和下一個值作用在獲得的隨后結果上,最后減少我們的序列為一個單一的返回值:如果初始值init給定,第一個比較會是init和第一個序列元素而不是序列的頭兩個元素。
說明:
在Python3.0里面必須導入functools模塊,from functools import reduce。reduce返回的必然是一個值,可以有初始值。
當需要對一個列表進行一些計算并返回結果時,reduce是個非常有用的函數。
舉個例子,當你需要計算一個整數列表的乘積時,通常在python中你可能會使用基本的for循環來完成這個任務。
現在我們來試試reduce:
from functools import reduce
product = reduce((lambda x, y: x * y), [1, 2, 3, 4])
# 輸出為:
24
例子:
>>> reduce(lambda x,y: x+y, [47,11,42,13])
113
其實現過程如下圖所示:
其實現過程等同下面的:
>>> import operator
>>> reduce(operator.add,[47,11,42,13])
113
注意:
- func()函數不能為None,否則報錯。
>>> reduce(None,[1,2,3,4])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
- func(x,y)只能有兩個參數,否則報錯。
>>> reduce(lambda x,y,z: x+y+z, [1,2,3,4],9)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: <lambda>() takes exactly 3 arguments (2 given)
reduce的邏輯實現:
def reduce(func,seq,init=None):
l_seq = list(seq)
if init is None:
res = l_seq.pop(0)
else:
res = init
for item in l_seq:
res = func(res,item) # func(res,item)作為結果集傳給res
return res # 返回結果集
print reduce(lambda x,y:x+y,[1,2,3,4]) # 結果為10
print reduce(lambda x,y:x+y,[1,2,3,4],10) # 結果為20,init初始值為10
5 apply
>>> help(apply)
Help on built-in function apply in module __builtin__:
apply(...)
apply(object[, args[, kwargs]]) -> value
Call a callable object with positional arguments taken from the tuple args, and keyword arguments
taken from the optional dictionary kwargs. Note that classes are callable, as are instances with
a __call__() method.Deprecated since release 2.3. Instead, use the extended call syntax:
function(*args, **keywords).
用途:
當一個函數的參數存在于一個元組或者一個字典中時,用來間接的調用這個函數,元組或者字典中的參數按照順序傳遞。
說明:
- args是一個包含按照函數所需參數傳遞的位置參數的一個元組,假如func(a=1,b=2),那么這個元組中就必須嚴格按照這個參數的位置順序進行傳遞(a=3,b=4),而不能是(b=4,a=3)這樣的順序。
- kwargs是一個包含關鍵字參數的字典,而其中args如果不傳遞,kwargs需要傳遞,則必須在args的位置留空。
apply函數的返回值就是func函數的返回值。其實apply(func,args,kwargs)從Python2.3開始,已經被function(*args,**kwargs)代替了。
例1. 常規使用
def func1(): # 無參函數
print 'No Args!'
def func2(arg1,arg2): # 兩個參數
print arg1,arg2
def func3(arg1=1,arg2=2): # 帶字典函數
print arg1,arg2
if __name__=='__main__':
apply(func1)
apply(func2,('Hello','World!'))
apply(func3,(),{'arg1':'This is param1','arg2':'This is param2'}) # 注意元組參數為()
既然可以用function(args,*kwargs)來代替apply(),那么apply有什么好處呢,幾個看得見的好處:
- 如果函數名,變量名太長的話,用apply()還是很方便的。
- 如果不能確認有多少變量在args里面時,則必須使用apply,它能動態加載變量及函數。
# Sorry about the long variable names
args = function_returning_list_of_numbers()
func = function_returning_a_function_which_operates_on_a_list_of_numbers()
# You want to do f(arg[0], arg[1], ...) but you don't know how many arguments are in 'args'. For this you have to use 'apply': result = apply(func, args)
3.如果函數名作為一個對象來傳遞時,用apply()很方便。
def test(f,a,b):
print 'test'
print f(a,b)
test(func,a,b)
可以看出,test函數的第一個參數f就是一個函數對象。我們將func傳遞給f,那么test中的f()所做的實際上就是func()所實現的功能。這樣,就大大提供了程序的靈活性。假如我們有另外一個函數取代func,就可以使用相同的test函數。
test(lambda x,y: x ** 2 + y,2,3)
>>> test
7
6 zip
>>> help(zip)
Help on built-in function zip in module __builtin__:
zip(...)
zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]
Return a list of tuples, where each tuple contains the i-th element from each of the argument
sequences. The returned list is truncated in length to the length of the shortest argument sequence.
用途:
返回一個元組列表,該元組按順序包含每個序列的相應元素,以最小的一個為準。
說明:
zip()是Python的一個內建函數,它接受一系列可迭代的對象作為參數,將對象中對應的元素打包成一個個tuple(元組),然后返回由這些tuples組成的list(列表)。若傳入參數的長度不等,則返回list的長度等于參數中長度最短的對象的長度。
例子:
>>> zip(range(5),range(1,20,2))
[(0, 1), (1, 3), (2, 5), (3, 7), (4, 9)]
>>> x=(1,2,3); y=(4,5);z=(6,)
>>> zip(x,y,z)
[(1, 4, 6)]
zip的邏輯實現:
def zip(*iterables):
sentinel = object()
iterators = [iter(it) for it in iterables]
while iterators:
result = []
for it in iterators:
elem = next(it, sentinel)
if elem is sentinel:
return result.append(elem)
yield tuple(result)
如果您發現文中有不清楚或者有問題的地方,請在下方評論區留言,我會根據您的評論,更新文中相關內容,謝謝!