我們都知道Python之所有能在數(shù)據(jù)科學(xué)領(lǐng)域占有一席之地险毁,主要是數(shù)據(jù)分析三劍客:numpy霍衫、pandas候引、matplotlib這三個(gè)庫的功勞。而在這三個(gè)庫中敦跌,我覺得最核心澄干,用的最多的還是pandas。不管是在平時(shí)處理數(shù)據(jù)還是打比賽中柠傍,都要求能夠?qū)andas進(jìn)行熟練的應(yīng)用麸俘。基于此惧笛,筆者參加了Datawhale開源社區(qū)組織的Pandas學(xué)習(xí)从媚,目標(biāo)就是爆肝一個(gè)月,精通Pandas!
從本期開始患整,我們就開始來系統(tǒng)學(xué)習(xí)并梳理一下Pandas的知識拜效。我們將按照下面的大綱分10期進(jìn)行。我相信通過通過10期豐富的案例學(xué)習(xí)并级,掌握并熟練運(yùn)用Pandas拂檩,水到渠成。
- Pandas基礎(chǔ)
- 索引
- 分組
- 變形
- 連接
- 缺失數(shù)據(jù)
- 文本數(shù)據(jù)
- 分類數(shù)據(jù)
- 時(shí)序數(shù)據(jù)
- 綜合練習(xí)
本期作為第一期嘲碧,主要是熟悉一些基礎(chǔ)知識稻励,為后期的學(xué)習(xí)做準(zhǔn)備。主要包括Python中的一些常用函數(shù)和numpy庫的一些操作愈涩。
1.1 列表推導(dǎo)式
列表推導(dǎo)式是Python語言的一大特色望抽,可以快速簡潔的創(chuàng)建列表。
1.1.1 基本格式:
[* for i in k]: * 可以是一個(gè)函數(shù)履婉,變量為i(也可以與i無關(guān))煤篙,k為一個(gè)可迭代對象,如列表毁腿。
應(yīng)用: 1. 一句代碼輸出一個(gè)1到5的立方
- 一句代碼創(chuàng)建一個(gè)列表辑奈,包含10個(gè)60-100的隨機(jī)整數(shù)
# 一句代碼輸出一個(gè)1到5的立方
[i**3 for i in range(1,6)]
>>>[1, 8, 27, 64, 125]
# 一句代碼創(chuàng)建一個(gè)列表,包含10個(gè)60-100的隨機(jī)整數(shù)(模擬學(xué)生成績)
import random
[random.randint(60,100) for _ in range(10)]
>>> [76, 89, 62, 83, 61, 80, 89, 99, 76, 78]
1.1.2 for循環(huán)嵌套
列表推導(dǎo)式中的for循環(huán)支持嵌套功能已烤。
舉例: 現(xiàn)有3個(gè)列表分別保存了顧客的姓名鸠窗,衣服的顏色,尺碼胯究,用一句代碼輸出所有顧客和衣服顏色尺碼的組合
names = ['zhangsan', 'lisi', 'wangba']
color = ['red', 'yellow']
size = ['S', 'M', 'L']
[name + '-' + c + '-' + s for name in names for c in color for s in size]
>>>
['zhangsan-red-S',
'zhangsan-red-M',
'zhangsan-red-L',
'zhangsan-yellow-S',
'zhangsan-yellow-M',
'zhangsan-yellow-L',
'lisi-red-S',
'lisi-red-M',
'lisi-red-L',
'lisi-yellow-S',
'lisi-yellow-M',
'lisi-yellow-L',
'wangba-red-S',
'wangba-red-M',
'wangba-red-L',
'wangba-yellow-S',
'wangba-yellow-M',
'wangba-yellow-L']
上面的代碼等價(jià)于:
for name in names:
for c in color:
for s in size:
print(name + '-' + c + '-' + 's')
>>>
zhangsan-red-s
zhangsan-red-s
zhangsan-red-s
zhangsan-yellow-s
zhangsan-yellow-s
zhangsan-yellow-s
lisi-red-s
lisi-red-s
lisi-red-s
lisi-yellow-s
lisi-yellow-s
lisi-yellow-s
wangba-red-s
wangba-red-s
wangba-red-s
wangba-yellow-s
wangba-yellow-s
wangba-yellow-s
1.1.3 篩選功能
列表推導(dǎo)式中for循環(huán)后還可以加入if (或者if...else...)進(jìn)行篩選 稍计。
舉例: 一句代碼輸出0-100內(nèi)可以被7整除的整數(shù)
# 輸出1-100內(nèi)可以被7整除的數(shù):
[i for i in range(1,101) if i%7 == 0]
>>>
[7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98]
綜合上面的案例,我們可以清晰的看到列表推導(dǎo)式的簡潔與優(yōu)雅裕循!同時(shí)也體現(xiàn)Python的強(qiáng)大之處臣嚣。
1.2 lambda匿名函數(shù)
我們都知道函數(shù)在python世界中屬于一等公民净刮,具有很高的權(quán)限。對于經(jīng)常需要重復(fù)使用的代碼塊硅则,一般都要優(yōu)先考慮通過函數(shù)來實(shí)現(xiàn)淹父。但是當(dāng)我們想要使用一個(gè)簡單定義的,或者只需要調(diào)用一兩次的函數(shù)時(shí)怎虫,取名并編寫一個(gè)完整的函數(shù)塊就顯得多余弹灭。這時(shí)候lambda匿名函數(shù)就有了用武之地。
格式: lambda [arg1 [,arg2, ... argN]] : expression
這里的lamdbda是系統(tǒng)保留的關(guān)鍵字揪垄, [arg1 [,arg2, ... argN]]是參數(shù)列表,它的結(jié)構(gòu)與Python中函數(shù)(function)的參數(shù)列表是一樣的逻翁。expression是一個(gè)關(guān)于參數(shù)的表達(dá)式饥努。表達(dá)式中出現(xiàn)的參數(shù)需要在argument_list中有定義,并且表達(dá)式只能是單行的八回。
舉例:例如我們定義一個(gè)函數(shù)酷愧,將字符串中的所有字母大寫輸出
def str_capital(s):
return str.upper(s)
str_capital('datawhale')
>>>
'DATAWHALE'
如果改用匿名函數(shù)的寫法:
upper = lambda x: str.upper(x)
upper('datawhale')
>>>
'DATAWHALE'
對比一下可以看到匿名函數(shù)有如下優(yōu)點(diǎn):
- 可以直接在使用的地方定義,如果需要修改缠诅,直接找到修改即可溶浴,方便以后代碼的維護(hù)工作
- 語法結(jié)構(gòu)簡單,不用使用def 函數(shù)名(參數(shù)名):這種方式定義管引,直接使用lambda 參數(shù):返回值 定義即可
但是需要注意的是lambda匿名函數(shù)讓程序簡潔士败,但是并不能讓程序高效,這個(gè)也是很多程序員反對使用lambda的原因褥伴。
1.3 map()方法
在Python中谅将,匿名函數(shù)lambda經(jīng)常和map()、reduce()和filter()三個(gè)應(yīng)用于序列的內(nèi)置函數(shù)聯(lián)合使用重慢,用于對序列進(jìn)行遍歷饥臂、遞歸計(jì)算以及篩選。這其中似踱,最常用的就是map方法隅熙。在Python中,map()函數(shù)的本質(zhì)是一種映射,即對輸入其中的可迭代對象(列表)中每個(gè)元素執(zhí)行定義的映射核芽。例如我們編寫了一個(gè)將給定的字符串大寫輸出的函數(shù)囚戚,在使用該函數(shù)將若干字符串大寫輸出
def str_capital(s):
return str.upper(s)
L1 = ['I', 'like', 'Datawhale']
L2 = []
for s in L1:
L2.append(str_capital(s))
L2
>>>
['I', 'LIKE', 'DATAWHALE']
如果我們用map()替代for循環(huán):
L3 = map(str_capital, L1)
list(L3)
>>>
['I', 'LIKE', 'DATAWHALE']
可以看到更加簡潔!需要注意的是map()方法返回的是一個(gè)map()對象狞洋,需要用list()方法輸出其中的元素弯淘。上面我們說了map經(jīng)常和lambda匿名函數(shù)結(jié)合使用,如下:
L4 = map(lambda x: str.upper(x), L1)
list(L4)
>>>
['I', 'LIKE', 'DATAWHALE']
優(yōu)雅吉懊!
1.4 zip方法
我們都知道zip是一個(gè)文件解壓程序庐橙,同樣的假勿,在python中zip()函數(shù)就有點(diǎn)類似于解壓縮包的感覺:傳入一個(gè)列表或者其他可迭代對象,依次從中選取一個(gè)組成新的元組輸出态鳖。下面舉例:
a = [3,4,5,6]
b = ['a', 'b', 'c']
s1 = {'zhangsan': 20, 'lisi': 25}
print(zip(a))
print('*' * 10)
print(list(zip(a)))
print(list(zip(b)))
print(list(zip(s1)))
>>>
<zip object at 0x000001A7D4FF7940>
**********
[(3,), (4,), (5,), (6,)]
[('a',), ('b',), ('c',)]
[('zhangsan',), ('lisi',)]
可以看到zip的輸出也是一個(gè)zip對象转培,需要用list查看其中的元素。
當(dāng)zip()函數(shù)有兩個(gè)參數(shù)時(shí) 浆竭,如zip(a,b),則分別從a和b依次各取出一個(gè)元素組成元組邦泄,再將依次組成的元組組合成一個(gè)新的迭代器。如:
print(list(zip(a,b)))
>>>
[(3, 'a'), (4, 'b'), (5, 'c')]
這樣設(shè)計(jì)有個(gè)特殊的用途顺囊,用于矩陣(二維數(shù)組)的加減和點(diǎn)乘,舉例如下:
import numpy as np
m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
n = [[2, 2, 2], [3, 3, 3], [4, 4, 4]]
# 矩陣點(diǎn)乘
print('=*'*10 + "矩陣點(diǎn)乘" + '=*'*10)
print(np.array([x*y for a, b in zip(m, n) for x, y in zip(a, b)]).reshape(3,3))
# 矩陣相加,相減雷同
print('=*'*10 + "矩陣相加,相減" + '=*'*10)
print(np.array([x+y for a, b in zip(m, n) for x, y in zip(a, b)]).reshape(3,3))
>>>
=*=*=*=*=*=*=*=*=*=*矩陣點(diǎn)乘=*=*=*=*=*=*=*=*=*=*
[[ 2 4 6]
[12 15 18]
[28 32 36]]
=*=*=*=*=*=*=*=*=*=*矩陣相加,相減=*=*=*=*=*=*=*=*=*=*
[[ 3 4 5]
[ 7 8 9]
[11 12 13]]
知識鏈接:矩陣點(diǎn)乘
矩陣點(diǎn)乘: 對應(yīng)元素相乘,要求兩個(gè)矩陣的形狀必須相同特碳。這個(gè)要和矩陣叉乘區(qū)分開來诚亚。
2. Numpy復(fù)習(xí)回顧
pandas是基于numpy來實(shí)現(xiàn)高效計(jì)算的午乓,因而在學(xué)習(xí)pandas之前有必要先把之前學(xué)習(xí)的numpy的知識溫習(xí)一下站宗,這里總結(jié)了一些numpy一些常用的知識點(diǎn)
2.1 np.array
np里面最基本的數(shù)據(jù)結(jié)構(gòu)是array(數(shù)組)益愈,構(gòu)造也非常簡單梢灭,np.array即可。下面總結(jié)幾種特殊的array
- 等差序列
- np.linspace(起始蒸其,終止(包含)或辖,樣本個(gè)數(shù)): 適用于提前知道需要?jiǎng)?chuàng)建多少個(gè)樣本的情況
- np.arange(起始枣接,終止(不包含),步長): 適用于提前知道相鄰間隔的情況
注意 np.arange和python數(shù)組中的range不要混淆了但惶。range只能生成整數(shù)數(shù)列,而np.arange可以生成小數(shù)數(shù)列
import numpy as np
a = np.linspace(1,100,10)
b = np.arange(1,10,1.5)
print(a)
print(b)
>>>
[ 1. 12. 23. 34. 45. 56. 67. 78. 89. 100.]
[1. 2.5 4. 5.5 7. 8.5]
- 特殊矩陣县爬,包括zeros/ones/eye/full等
直接上代碼參考:
- 特殊矩陣县爬,包括zeros/ones/eye/full等
print('3行4列全0矩陣')
print(np.zeros((3,4)))
print('*' * 10)
print('3行3列全1矩陣')
print(np.ones((3, 3)))
print('*' * 10)
print('3行3列的單位矩陣')
print(np.eye(3))
print('*' * 10)
print('指定維度的/數(shù)值填充矩陣')
print(np.full((2,3), 6))
>>>
3行4列全0矩陣
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
**********
3行3列全1矩陣
[[1. 1. 1.]
[1. 1. 1.]
[1. 1. 1.]]
**********
3行3列的單位矩陣
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
**********
指定維度的/數(shù)值填充矩陣
[[6 6 6]
[6 6 6]]
- 隨機(jī)矩陣
- np.random.rand() : 取值0-1之間的隨機(jī)分布添谊,這里不要傳元組财喳,直接指定不同維度的個(gè)數(shù)即可
- np.random.randn(): 0~1標(biāo)準(zhǔn)正態(tài)分布
- np.random.randint(low,high,size) :指定生成隨機(jī)整數(shù)的最小值最大值和維度大小
- np.random.choice(): 可以從給定的列表中,以一定概率和方式抽取結(jié)果扎瓶,當(dāng)不指定概率時(shí)為均勻采樣泌枪,默認(rèn)抽取方式為有放回抽樣
- np.random.seed(0) : 設(shè)置種子,就相當(dāng)是設(shè)定了隨機(jī)值碌燕,之后每次隨機(jī)都一樣
2. 練習(xí)題:
-
使用列表推導(dǎo)式完成矩陣乘法:
矩陣乘法定義:
一般的矩陣乘法根據(jù)公式,可以由三重循環(huán)寫出:
使用列表推導(dǎo)式來替代for循環(huán)完成
# 先定義零個(gè)矩陣
M1 = np.random.randint(1,10,10).reshape(2,5)
M2 = np.random.randint(1,10,10).reshape(5,2)
print(M1)
print('-' * 5)
print(M2)
M1@M2 # 矩陣乘法
>>>
[[6 1 2 8 5]
[6 1 7 9 4]]
-----
[[6 2]
[7 7]
[1 4]
[7 1]
[8 3]]
array([[141, 50],
[145, 68]])
# 使用列表推導(dǎo)式來完成
[[sum([M1[i][k] * M2[k][j] for k in range(M1.shape[1])]) for j in range(M2.shape[1])] for i in range(M1.shape[0])]
>>>
[[141, 50], [145, 68]]
-
更新矩陣
設(shè)矩陣 Am×n 愈捅,現(xiàn)在對 A 中的每一個(gè)元素進(jìn)行更新生成矩陣 B 慈鸠,更新方法是
例如下面的矩陣為 A ,則 =5×(1/4+1/5+1/6)=37/12 林束,請利用 Numpy 高效實(shí)現(xiàn)稽亏。
解答:
A = np.arange(1,10).reshape(3,3)
B = A*(1/A).sum(1).reshape(-1,1)
使用內(nèi)置的函數(shù)
B = A.sum(0) * A.sum(1).reshape(-1,1) / A.sum()
print(B)
res = ((A-B) ** 2 / B).sum()
print(res)
參考:開源內(nèi)容Joyful Pandas, 作者 DataWhale耿遠(yuǎn)昊
另外,更多精彩內(nèi)容也可以微信搜索胖腾,并關(guān)注公眾號:‘Python數(shù)據(jù)科學(xué)家之路“ ,期待您的到來和我交流