斷更了一周,因為上周連續(xù)幾天掉粉,有點玻璃心了,再加上最近課程進度有點慢,更太快的話節(jié)奏會亂,所以就停了停。由于課程是一三五一周上三次,所以之后我會在二四六更新。
至于我的玻璃心,也差不多修好了。寫筆記本來就是為了自己學,能幫到別人更好,幫不到也就隨緣了。自己學會最重要,其他的都不重要。
這節(jié)課是關于數(shù)據(jù)分析最重要的一個 Python 庫 —— Pandas,基本上大多數(shù)數(shù)據(jù)分析相關的操作都是用 Pandas 來做的。所以這節(jié)課非常重要。由于大多數(shù)知識點都記在代碼注釋里了,所以正文內(nèi)容比較少,全是大段大段的代碼,所以正在跟著學習的同學一定要把這些代碼一行一行地敲下來,才能對這些細碎的知識點有直觀的理解和把握。
好了,廢話不多說,我們開始吧~
課程大綱:
- Pandas簡介
- Series對象
- DataFrame的創(chuàng)建
(1)DataFrame的創(chuàng)建
(2)DataFrame對象常用屬性
(3)dataframe修改index、columns
(4)添加數(shù)據(jù) - 數(shù)據(jù)處理
- 數(shù)據(jù)合并
- 多層索引(拓展)
- 時間序列
- 分組聚合
- 分組案例
課前準備
安裝 Pandas 庫:
pip install -U pandas -i https://pypi.douban.com/simple
一、Pandas 簡介
Pandas 是基于 NumPy 創(chuàng)建的一種用于數(shù)據(jù)分析的工具,它納入了大量的庫和一些標準的數(shù)據(jù)模型,提供了高效操作大型數(shù)據(jù)集所需要的工具,包括能使我們快速便捷地處理數(shù)據(jù)的各種函數(shù)和方法。
Pandas 主要基于兩種數(shù)據(jù)類型:Series 和 Dataframe。
Series 是 Pandas 中最基本的對象,我們可以把它理解為一種一維數(shù)組。事實上,Series 基本上就是基于 NumPy 的數(shù)組對象來的。不過,和 NumPy 的數(shù)組不同,Series 能為數(shù)據(jù)自定義標簽,也就是索引(index),然后通過索引來訪問數(shù)組中的數(shù)據(jù)。
Dataframe 是一個二維的表結(jié)構(gòu)。Pandas 的 dataframe 可以存儲許多種不同的數(shù)據(jù)類型,并且每一個坐標軸都有自己的標簽。你可以把它想象成一個 series 的字典項。
二、Series 對象
1、Series 的創(chuàng)建
import pandas as pd
from pandas import Series,DataFrame
import numpy as np
# 創(chuàng)建Series對象并省略索引
'''
index 參數(shù)是可省略的,你可以選擇不輸入這個參數(shù)。
如果不帶 index 參數(shù),Pandas 會自動用默認 index 進行索引,類似數(shù)組,索引值是 [0, ..., len(data) - 1]
'''
sel = Series([1,2,3,4])
print(sel)
# 通常我們會自己創(chuàng)建索引
# sel = Series(data = [1,2,3,4], index = ['a','b','c','d'])
sel = Series(data = [1,2,3,4], index = list('abcd'))
print(sel)
# 獲取內(nèi)容
print(sel.values)
# 獲取索引
print(sel.index)
# 獲取索引和值對
print(list(sel.iteritems()))
# 將字典轉(zhuǎn)換為
Series dict={"red":100,"black":400,"green":300,"pink":900} se3=Series(dict)
print(se3)
# Series數(shù)據(jù)獲取
sel = Series(data = [1,2,3,4], index = list('abcd'))
print(sel)
# Series對象同時支持位置和標簽兩種方式獲取數(shù)據(jù)
print('索引下標',sel['c'])
print('位置下標',sel[2])
# 獲取不連續(xù)的數(shù)據(jù)
print('索引下標',sel[['a','c']])
print('位置下標',sel[[1,3]])
# 可以使用切片或取數(shù)據(jù)
print('位置切片',sel[1:3])# 左包含右不包含
print('索引切片',sel['b':'d'])# 左右都包含
# 重新賦值索引的值
sel.index = list('dcba')
print(sel)
# ReIndex重新索引,會返回一個新的Series(調(diào)用reindex將會重新排序,缺失值則用NaN填補)
print(sel.reindex(['b','a','c','d','e']))
# Drop丟棄指定軸上的項
se1=pd.Series(range(10,15))
print(se1)
print(se1.drop([2,3]))
2、Series 進行算術(shù)運算操作
'''
對 Series 的算術(shù)運算都是基于 index 進行的。
我們可以用加減乘除(+ - * /)這樣的運算符對兩個 Series 進行運算,Pandas 將會根據(jù)索引 index,對響應的數(shù)據(jù)進行計算,結(jié)果將會以浮點數(shù)的形式存儲,以避免丟失精度。如果 Pandas 在兩個Series 里找不到相同的 index,對應的位置就返回一個空值 NaN
'''
series1 = pd.Series([1,2,3,4],['London','HongKong','Humbai','lagos'])
series2 = pd.Series([1,3,6,4],['London','Accra','lagos','Delhi'])
print(series1-series2)
print(series1+series2)
print(series1*series2)
# 同樣也支持numpy的數(shù)組運算
sel = Series(data = [1,6,3,5], index = list('abcd'))
print(sel[sel>3]) # 布爾數(shù)組過濾
print(sel*2) # 標量乘法
print(np.square(sel))
三、DataFrame 對象
DataFrame(數(shù)據(jù)表)是一種 2 維數(shù)據(jù)結(jié)構(gòu),數(shù)據(jù)以表格的形式存儲,分成若干行和列。通過 DataFrame,我們能很方便地處理數(shù)據(jù)。常見的操作比如選取、替換行或列的數(shù)據(jù),還能重組數(shù)據(jù)表、修改索引、多重篩選等。我們基本上可以把 DataFrame 理解成一組采用同樣索引的 Series 的集合。調(diào)用 DataFrame() 可以將多種格式的數(shù)據(jù)轉(zhuǎn)換為 DataFrame 對象,它的三個參數(shù) data、index 和columns 分別為數(shù)據(jù)、行索引和列索引。
1、DataFrame的創(chuàng)建
# 1. 創(chuàng)建DataFrame
# 使用二維數(shù)組
df1 = DataFrame(np.random.randint(0,10,(4,4)),index= 1,2,3,4],columns= ['a','b','c','d'])
print(df1)
# 使用字典創(chuàng)建(行索引由index決定,列索引由字典的鍵決定)
dict={
'Province': ['Guangdong', 'Beijing', 'Qinghai', 'Fujian'],
'pop': [1.3, 2.5, 1.1, 0.7],
'year': [2018, 2018, 2018, 2018]
}
df2=pd.DataFrame(dict,index=[1,2,3,4])
print(df2)
# 使用 from_dict
dict2={"a":[1,2,3],"b":[4,5,6]}
df6=pd.DataFrame.from_dict(dict2)
print(df6)
#索引相同的情況下,相同索引的值會相對應,缺少的值會添加NaN data = {
'Name':pd.Series(['zs','ls','we'],index=['a','b','c']),
'Age':pd.Series(['10','20','30','40'],index=['a','b','c','d']),
'country':pd.Series(['中國','日本','韓國'],index=['a','c','b'])
}
df = pd.DataFrame(data)
print(df)
# to_dict()方法將DataFrame對象轉(zhuǎn)換為字典
dict = df.to_dict()
print(dict)
2、DataFrame對象常用屬性
import pandas as pd
from pandas import Series,DataFrame import numpy as np
# dataframe常用屬性df_dict = {
'name':['James','Curry','Iversion'],
'age':['18','20','19'],
'national':['us','China','us']
}
df = pd.DataFrame(data=df_dict,index=['0','1','2'])
print(df)
# 獲取行數(shù)和列數(shù)
print(df.shape)
# 獲取行索引
print(df.index.tolist())
# 獲取列索引
print(df.columns.tolist())
# 獲取數(shù)據(jù)類型
print(df.dtypes)
# 獲取數(shù)據(jù)的維度
print(df.ndim)
# values屬性也會以二維ndarray的形式返回DataFrame的數(shù)據(jù)print(df.values)
# 展示df的概覽
print(df.info())
# 顯示頭幾行,默認顯示5行
print(df.head(2))
# 顯示后幾行
print(df.tail(1))
# 獲取DataFrame的列
print(df['name'])
#因為我們只獲取一列,所以返回的就是一個 Series print(type(df['name']))
# 如果獲取多個列,那返回的就是一個 DataFrame 類型:
print(df[['name','age']])
print(type(df[['name','age']]))
# 獲取一行
print(df[0:1])
# 獲取多行
print(df[1:3])
# 取多行里面的某一列(不能進行多行多列的選擇)
print(df[1:3][['name','age']])
# 注意: df[]只能進行行選擇,或列選擇,不能同時多行多列選擇。
'''
注意:df.loc 通過標簽索引行數(shù)據(jù) df.iloc 通過位置獲取行數(shù)據(jù)
'''
# 獲取某一行某一列的數(shù)據(jù)
print(df.loc['0','name'])
# 一行所有列
print(df.loc['0',:])
# 某一行多列的數(shù)據(jù)
print(df.loc['0',['name','age']])
# 選擇間隔的多行多列
print(df.loc[['0','2'],['name','national']])
# 選擇連續(xù)的多行和間隔的多列
print(df.loc['0':'2',['name','national']])
# 取一行
print(df.iloc[1])
# 取連續(xù)多行
print(df.iloc[0:2])
# 取間斷的多行
print(df.iloc[[0,2],:])
# 取某一列
print(df.iloc[:,1])
# 某一個值
print(df.iloc[1,0])
# 修改值
df.iloc[0,0]='panda'
print(df)
# dataframe中的排序方法
df = df.sort_values(by='age',ascending=False)
# ascending=False : 降序排列,默認是升序
print(df)
3、dataframe 修改 index、columns
df1 = pd.DataFrame(np.arange(9).reshape(3, 3), index = ['bj', 'sh', 'gz'], columns=['a', 'b', 'c'])
print(df1)
# 修改 df1 的 index
print(df1.index)
# 可以打印出print的值,同時也可以為其賦值
df1.index = ['beijing', 'shanghai', 'guangzhou']
print(df1)
# 自定義map函數(shù)(x是原有的行列值)
def test_map(x):
return x+'_ABC'
# inplace:布爾值,默認為False。指定是否返回新的DataFrame。如果為True,則在原df上修改,返回值為None。
print(df1.rename(index=test_map, columns=test_map, inplace=True))
# 同時,rename 還可以傳入字典,為某個 index 單獨修改名稱
df3 = df1.rename(index={'bj':'beijing'}, columns = {'a':'aa'})
print(df3)
# 列轉(zhuǎn)化為索引
df1=pd.DataFrame({'X':range(5),'Y':range(5),'S':list("abcde"),'Z':[1,1,2,2,2]})
print(df1)
# 指定一列為索引 (drop=False 指定同時保留作為索引的列)
result = df1.set_index('S',drop=False)
result.index.name=None
print(result)
# 拓展: reset_index是把索引變成列
# 行轉(zhuǎn)為列索引
result = df1.set_axis(df1.iloc[0],axis=1,inplace=False) result.columns.name=None
print(result)
4、添加數(shù)據(jù)
# 增加數(shù)據(jù)
df1 = pd.DataFrame([['Snow','M',22],['Tyrion','M',32],['Sansa','F',18], ['Arya','F',14]],columns=['name','gender','age'])
# 在數(shù)據(jù)框最后加上score一列
df1['score']=[80,98,67,90] # 增加列的元素個數(shù)要跟原數(shù)據(jù)列的個數(shù)一樣
print(df1)
# 在具體某個位置插入一列可以用insert的方法
# 語法格式:列表.insert(index, obj)
# index --->對象 obj 需要插入的索引位置。
# obj ---> 要插入列表中的對象(列名)
col_name=df1.columns.tolist() # 將數(shù)據(jù)框的列名全部提取出來存放在列表里
col_name.insert(2,'city') # 在列索引為2的位置插入一列,列名為:city,剛插入時不會有值,整列都是NaN
df1=df1.reindex(columns=col_name) # DataFrame.reindex() 對原行/列索引重新構(gòu)建索引值
print(df1)
df1['city']=['北京','山西','湖北','澳門'] # 給city列賦值
print(df1)
# df中的insert,插入一列
'''
df.insert(iloc,column,value) iloc:要插入的位置
colunm:列名
value:值
'''
df1.insert(2,'score',[80,98,67,90])
print(df1)
# 插入一行(會被覆蓋,可以進行分割合并的方式)
row=['111','222','333']
df1.iloc[1]=row
print(df1)
# 增加數(shù)據(jù)
df1 = pd.DataFrame([['Snow','M',22],['Tyrion','M',32],['Sansa','F',18], ['Arya','F',14]], columns=['name','gender','age'])
# 先創(chuàng)建一個DataFrame,用來增加進數(shù)據(jù)框的最后一行
new=pd.DataFrame({'name':'lisa','gender':'F', 'age':19},index=[0])
print(new)
# print("-------在原數(shù)據(jù)框df1最后一行新增一行,用append方法--------------------------------------------------------------------- ")
df1=df1.append(new,ignore_index=True) # ignore_index=False,表示不按原來的索引,從0開始自動遞增
print(df1)
# 合并
'''
objs:合并對象
axis:合并方式,默認0表示按列合并,1表示按行合并
ignore_index:是否忽略索引
'''
df1 = pd.DataFrame(np.arange(6).reshape(3,2),columns=['four','five'])
df2 = pd.DataFrame(np.arange(6).reshape(2,3),columns=['one','two','three']) print(df2)
# # 按行合并
result = pd.concat([df1,df2],axis=1)
print(result)
# # 按列合并
result = pd.concat([df1,df2],axis=0,ignore_index=True)
print(result)
# DataFrame的刪除
'''
lables:要刪除數(shù)據(jù)的標簽
axis:0表示刪除行,1表示刪除列,默認0
inplace:是否在當前df中執(zhí)行此操作
'''
df2 = pd.DataFrame(np.arange(9).reshape(3,3),columns=['one','two','three'])
print(df2)
df3=df2.drop(['one'],axis=1, inplace=True)
# df3=df2.drop([0,1],axis=0, inplace=False)
print(df2)
print(df3)
四、數(shù)據(jù)處理
from numpy import nan as NaN # 通過**dropna()**濾除缺失數(shù)據(jù): se=pd.Series([4,NaN,8,NaN,5]) #
print(se)
# print(se.dropna())
# print(se.notnull())
# print(se.isnull())
# # 通過布爾序列也能濾除:
# print(se[se.notnull()])
# 2.2 處理DataFrame對象
df1=pd.DataFrame([[1,2,3],[NaN,NaN,2],[NaN,NaN,NaN],[8,8,NaN]])
# print(df1)
# 默認濾除所有包含NaN:
# print(df1.dropna())
# 傳入how=‘a(chǎn)ll’濾除全為NaN的行:
# print(df1.dropna(how='all')) # 默認情況下是how='any',只要有nan就刪除
# 傳入axis=1濾除列:
# print(df1.dropna(axis=1,how="all"))
# 傳入thresh=n保留至少有n個非NaN數(shù)據(jù)的行:
# print(df1.dropna(thresh=1))
# 2.3 填充缺失數(shù)據(jù)
df1=pd.DataFrame([[1,2,3],[NaN,NaN,2],[NaN,NaN,NaN],[8,8,NaN]])
# print(df1)
# 用常數(shù)填充fillna
# print(df1.fillna(0))
#傳入inplace=True直接修改原對象:
# df1.fillna(0,inplace=True)
# print(df1)
# 通過字典填充不同的常數(shù)
# print(df1.fillna({0:10,1:20,2:30}))
# 填充平均值
print(df1.fillna(df1.mean()))
# 如果只填充一列
print(df1.iloc[:,1].fillna(5,inplace = True))
print(df1)
# 傳入 method=” “ 改變插值方式 : df2=pd.DataFrame(np.random.randint(0,10,(5,5))) df2.iloc[1:4,3]=NaN
df2.iloc[2:4,4]=NaN
# print(df2)
#用前面的值來填充ffill 用后面的值來填充bfill
# print(df2.fillna(method='ffill'))
# 傳入limit=” “限制填充行數(shù):
# print(df2.fillna(method='bfill',limit=1))
# 傳入axis=” “修改填充方向:
# print(df2.fillna(method="ffill",limit=1,axis=1))
# 2.4 移除重復數(shù)據(jù)
'''
DataFrame中經(jīng)常會出現(xiàn)重復行,利用duplicated()函數(shù)返回每一行判斷是否重復的結(jié)果(重復則為True)
'''
df1=pd.DataFrame({'A':[1,1,1,2,2,3,1],'B':list("aabbbca")})
print(df1)
# 判斷每一行是否重復(結(jié)果是bool值,TRUE代表重復的)
# print(df1.duplicated())
# 去除全部的重復行
# print(df1.drop_duplicates())
# # 指定列去除重復行
# print(df1.drop_duplicates(['A']))
# 保留重復行中的最后一行
# print(df1.drop_duplicates(['A'],keep='last'))
# 去除重復的同時改變DataFrame對象
# df1.drop_duplicates(['A','B'],inplace=True)
# print(df1)
五、數(shù)據(jù)合并
# 使用join合并,著重關注的是行的合并
import pandas as pd
df3=pd.DataFrame({'Red':[1,3,5],'Green':[5,0,3]},index=list('abc'))
df4=pd.DataFrame({'Blue':[1,9,8],'Yellow':[6,6,7]},index=list('cde')) print(df3)
print(df4)
# 簡單合并(默認是left左連接,以左側(cè)df3為基礎)
df3.join(df4,how='left')
# 右鏈接
df3.join(df4,how='right')
# 外鏈接
df3.join(df4,how='outer')
# 合并多個DataFrame對象
# df5=pd.DataFrame({'Brown':[3,4,5],'White':[1,1,2]},index=list('aed'))
# df3.join([df4,df5])
# 使用merge,著重關注的是列的合并
df1=pd.DataFrame({'名字':list('ABCDE'),'性別':['男','女','男','男','女'],'職稱':['副 教授','講師','助教','教授','助教']},index=range(1001,1006))
df1.columns.name='學院老師'
df1.index.name='編號'
print(df1)
df2=pd.DataFrame({'名字':list('ABDAX'),'課程':['C++','計算機導論','匯編','數(shù)據(jù)結(jié)構(gòu)','馬克思原理'],'職稱':['副教授','講師','教授','副教授','講師']},index= [1001,1002,1004,1001,3001])
df2.columns.name='課程'
df2.index.name='編號'
print(df2)
# 默認下是根據(jù)左右對象中出現(xiàn)同名的列作為連接的鍵,且連接方式是how=’inner’
# print(pd.merge(df1,df2)) # 返回匹配的
# 指定列名合并
pd.merge(df1,df2,on='名字',suffixes=['_1','_2']) # 返回匹配的
# 連接方式,以左側(cè)為準
pd.merge(df1,df2,how='left')
# 以右側(cè)為準
pd.merge(df1,df2,how='right')
# 所有
# pd.merge(df1,df2,how='outer')
# 根據(jù)多個鍵進行連接
pd.merge(df1,df2,on=['職稱','名字'])
拓展
# 軸向連接-Concat
# 1. Series對象的連接
# s1=pd.Series([1,2],index=list('ab'))
# s2=pd.Series([3,4,5],index=list('bde'))
# print(s1)
# print(s2)
# pd.concat([s1,s2])
#橫向連接
# pd.concat([s1,s2],axis=1)
# 用內(nèi)連接求交集(連接方式,共有’inner’,’left’,right’,’outer’) # pd.concat([s1,s2],axis=1,join='inner')
# 指定部分索引進行連接
# pd.concat([s1,s2],axis=1,join_axes=[list('abc')])
# 創(chuàng)建層次化索引
# pd.concat([s1,s2],keys=['A','B'])
#當縱向連接時keys為列名
# pd.concat([s1,s2],keys=['A','D'],axis=1)
# 2. DataFrame對象的連接
df3=pd.DataFrame({'Red':[1,3,5],'Green':[5,0,3]},index=list('abd'))
df4=pd.DataFrame({'Blue':[1,9],'Yellow':[6,6]},index=list('ce')) print(df3)
print(df4)
# pd.concat([df3,df4])
# pd.concat([df3,df4],axis=1,keys=['A','B'])
# 用字典的方式連接同樣可以創(chuàng)建層次化列索引
# pd.concat({'A':df3,'B':df4},axis=1)
六、多層索引
1、創(chuàng)建多層索引
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
# Series也可以創(chuàng)建多層索引
# s = Series(np.random.randint(0,150,size=6),index=list('abcdef'))
# print(s)
# s = Series(np.random.randint(0,150,size=6),
# index=[['a','a','b','b','c','c'],['期中','期末','期中','期末','期 中','期末']])
# print(s)
# DataFrame創(chuàng)建多層索引
# df1 = DataFrame(np.random.randint(0,150,size=(6,4)), columns = ['zs','ls','ww','zl'],
# index = [['python','python','math','math','En','En'],['期中','期末','期中','期末','期中','期末']])
# print(df1)
# 2. 特定結(jié)構(gòu)
# class1=['python','python','math','math','En','En']
# class2=['期中','期末','期中','期末','期中','期末']
# m_index2=pd.MultiIndex.from_arrays([class1,class2])
# df2=DataFrame(np.random.randint(0,150,(6,4)),index=m_index2) # print(df2)
# class1=['期中','期中','期中','期末','期末','期末']
# class2=['python','math','En','python','math','En'] # m_index2=pd.MultiIndex.from_arrays([class1,class2])
# df2=DataFrame(np.random.randint(0,150,(6,4)),index=m_index2) # print(df2)
# 3. product構(gòu)造
class1=['python','math','En'] class2=['期中','期末']
m_index2=pd.MultiIndex.from_product([class1,class2]) df2=DataFrame(np.random.randint(0,150,(6,4)),index=m_index2) print(df2)
2、多層索引對象的索引
#多層索引對象的索引操作
# series
# s = Series(np.random.randint(0,150,size=6),
# index=[['a','a','b','b','c','c'],['期中','期末','期中','期末','期 中','期末']])
# print(s)
# 取一個第一級索引
# print(s['a'])
# 取多個第一級索引
# print(s[['a','b']])
# 根據(jù)索引獲取值
# print(s['a','期末'])
# loc方法取值
# print(s.loc['a'])
# print(s.loc[['a','b']])
# print(s.loc['a','期末'])
# iloc方法取值(iloc計算的事最內(nèi)層索引)
# print(s.iloc[1])
# print(s.iloc[1:4])
# dataframe
class1=['python','math','En']
class2=['期中','期末']
m_index2=pd.MultiIndex.from_product([class1,class2]) df2=DataFrame(np.random.randint(0,150,(6,4)),index=m_index2) print(df2)
# 獲取列
# print(df2[0])
# 一級索引
# print(df2.loc['python'])
# 多個一級索引
# print(df2.loc[['python','math']])
# 取一行
# print(df2.loc['python','期末'])
# 取一值
# print(df2.loc['python','期末'][0])
# iloc是只取最內(nèi)層的索引
# print(df2.iloc[0])
七、時間序列
import pandas as pd import numpy as np
# 1. 生成一段時間范圍
'''
該函數(shù)主要用于生成一個固定頻率的時間索引,在調(diào)用構(gòu)造方法時,必須指定start、end、periods中的兩 個參數(shù)值,否則報錯。
時間序列頻率:
D 日歷日的每天
B 工作日的每天
H 每小時
T或min 每分鐘
S 每秒
L或ms 每毫秒
U 每微秒
M 日歷日的月底日期
BM 工作日的月底日期
MS 日歷日的月初日期
BMS 工作日的月初日期
'''
# date = pd.date_range(start='20190501',end='20190530')
# print(date)
# freq:日期偏移量,取值為string, 默認為'D', freq='1h30min' freq='10D'
# periods:固定時期,取值為整數(shù)或None
# date = pd.date_range(start='20190501',periods=10,freq='10D')
# print(date)
'''
根據(jù)closed參數(shù)選擇是否包含開始和結(jié)束時間closed=None,left包含開始時間,不包含結(jié)束時間,right與之相反。
'''
data_time =pd.date_range(start='2019-01-09',end='2019-01-14',closed='left')
print(data_time)
# 2. 時間序列在dataFrame中的作用
# 可以將時間作為索引
index = pd.date_range(start='20190101',periods=10)
df = pd.Series(np.random.randint(0,10,size = 10),index=index) print(df)
# truncate這個函數(shù)將before指定日期之前的值全部過濾出去,after指定日期之前的值全部過濾出去.
after = df.truncate(after='2019-01-8')
print(after)
long_ts = pd.Series(np.random.randn(1000),index=pd.date_range('1/1/2019',periods=1000))
# print(long_ts)
# 根據(jù)年份獲取
# result = long_ts['2020']
# print(result)
# 年份和日期獲取
# result = long_ts['2020-05']
# print(result)
# 使用切片
# result = long_ts['2020-05-01':'2020-05-06']
# print(result)
# 通過between_time()返回位于指定時間段的數(shù)據(jù)集
# index=pd.date_range("2018-03-17","2018-03-30",freq="2H")
# ts = pd.Series(np.random.randn(157),index=index)
# print(ts.between_time("7:00","17:00"))
# 這些操作也都適用于dataframe
# index=pd.date_range('1/1/2019',periods=100)
# df = pd.DataFrame(np.random.randn(100,4),index=index)
# print(df.loc['2019-04'])
# 6. 移位日期
ts = pd.Series(np.random.randn(10),index=pd.date_range('1/1/2019',periods=10)) print(ts)
# 移動數(shù)據(jù),索引不變,默認由NaN填充
# periods: 移動的位數(shù) 負數(shù)是向上移動
# fill_value: 移動后填充數(shù)據(jù)
ts.shift(periods=2,fill_value=100)
# 通過tshift()將索引移動指定的時間:
ts.tshift(2)
# 將時間戳轉(zhuǎn)化成時間根式 某一個時間到1970年01月01日 00:00:00的秒數(shù)或者毫秒數(shù)
pd.to_datetime(1554970740000,unit='ms')
# utc是協(xié)調(diào)世界時,時區(qū)是以UTC的偏移量的形式表示的,但是注意設置utc=True,是讓pandas對象具有時區(qū)性質(zhì),對于一列進行轉(zhuǎn)換的,會造成轉(zhuǎn)換錯誤
# unit='ms' 設置粒度是到毫秒級別的
# 時區(qū)名字
# import pytz
# print(pytz.common_timezones)
2019-5-1
pd.to_datetime(1554970740000,unit='ms').tz_localize('UTC').tz_convert('Asia/Shanghai')
# 處理一列
df = pd.DataFrame([1554970740000, 1554970800000, 1554970860000],columns = ['time_stamp']) pd.to_datetime(df['time_stamp'],unit='ms').dt.tz_localize('UTC').dt.tz_convert('Asia/Shanghai') # 先賦予標準時區(qū),再轉(zhuǎn)換到東八區(qū)
# 處理中文
pd.to_datetime('2019年10月10日',format='%Y年%m月%d日')
分組聚合
# 分組
import pandas as pd import numpy as np df=pd.DataFrame({
'name':['BOSS','Lilei','Lilei','Han','BOSS','BOSS','Han','BOSS'], 'Year':[2016,2016,2016,2016,2017,2017,2017,2017], 'Salary':[999999,20000,25000,3000,9999999,999999,3500,999999], 'Bonus':[100000,20000,20000,5000,200000,300000,3000,400000]
})
# print(df)
# 根據(jù)name這一列進行分組
# group_by_name=df.groupby('name') # print(type(group_by_name))
# 查看分組
# print(group_by_name.groups)
# 分組后的數(shù)量
# print(group_by_name.count())
# 查看分組的情況
# for name,group in group_by_name:
# print(name)# 組的名字
# print(group)# 組具體內(nèi)容
# 可以選擇分組
# print(group_by_name.get_group('BOSS'))
# 按照某一列進行分組, 將name這一列作為分組的鍵,對year進行分組
# group_by_name=df['Year'].groupby(df['name'])
# print(group_by_name.count())
# 按照多列進行分組
# group_by_name_year=df.groupby(['name','Year'])
# for name,group in group_by_name_year:
# print(name)# 組的名字
# print(group)# 組具體內(nèi)容
# 可以選擇分組
# print(group_by_name_year.get_group(('BOSS',2016)))
# 將某列數(shù)據(jù)按數(shù)據(jù)值分成不同范圍段進行分組(groupby)運算
df = pd.DataFrame({'Age': np.random.randint(20, 70, 100),'Sex': np.random.choice(['M', 'F'], 100)})
age_groups = pd.cut(df['Age'], bins=[19,40,65,100])
# print(age_groups)
print(df.groupby(age_groups).count())
# 按‘Age’分組范圍和性別(sex)進行制作交叉表
pd.crosstab(age_groups, df['Sex'])
## 聚合
'''
聚合函數(shù)
mean 計算分組平均值
count 分組中非NA值的數(shù)量
sum 非 NA 值的和
median 非NA值的算術(shù)中位數(shù)
std 標準差
var 方差
min 非NA值的最小值
max 非NA值的最大值
prod 非NA值的積
first 第一個非NA值
last 最后一個非NA值
mad 平均絕對偏差
mode 模
abs 絕對值
sem 平均值的標準誤差
skew 樣品偏斜度(三階矩)
kurt 樣品峰度(四階矩)
quantile 樣本分位數(shù)(百分位上的值)
cumsum 累積總和
cumprod 累積乘積
cummax 累積最大值
cummin 累積最小值
'''
df1=pd.DataFrame({'Data1':np.random.randint(0,10,5),'Data2':np.random.randint(10,20,5), 'key1':list('aabba'),'key2':list('xyyxy')})
print(df1)
# 按key1分組,進行聚合計算
# 注意:當分組后進行數(shù)值計算時,不是數(shù)值類的列(即麻煩列)會被清除
print(df1.groupby('key1').sum())
# 只算data1
# print(df1['Data1'].groupby(df1['key1']).sum())
# print(df1.groupby('key1')['Data1'].sum())
# 使用agg()函數(shù)做聚合運算
# print(df1.groupby('key1').agg('sum'))
# 可以同時做多個聚合運算
# print(df1.groupby('key1').agg(['sum','mean','std']))
# 可自定義函數(shù),傳入agg方法中 grouped.agg(func)
def peak_range(df):
# 返回數(shù)值范圍
return df.max() - df.min()
# print(df1.groupby('key1').agg(peak_range))
# 同時應用多個聚合函數(shù)
# print(df1.groupby('key1').agg(['mean', 'std', 'count', peak_range]))
# 默認列名為函數(shù)名
# print(df1.groupby('key1').agg(['mean', 'std', 'count', ('range', peak_range)])) # 通過元組提供新的列名
# 給每列作用不同的聚合函數(shù)
dict_mapping = { 'Data1':['mean','max'], 'Data2':'sum'}
df1.groupby('key1').agg(dict_mapping)
拓展 apply() 函數(shù):
# 拓展apply函數(shù)
# apply函數(shù)是pandas里面所有函數(shù)中自由度最高的函數(shù)
df1=pd.DataFrame({'sex':list('FFMFMMF'),'smoker':list('YNYYNYY'),'age':[21,30,17,37,40,18,26],'weight':[120,100,132,140,94,89,123]})
print(df1)
# 自定義函數(shù)
def bin_age(age):
if age >=18:
return 1
else:
return 0
# 抽煙的年齡大于等18的
# print(df1['age'].apply(bin_age))
# df1['age'] = df1['age'].apply(bin_age)
# print(df1)
# 取出抽煙和不抽煙的體重前二
def top(smoker,col,n=5):
return smoker.sort_values(by=col)[-n:]
df1.groupby('smoker').apply(top,col='weight',n=2)
九、分組案例
# 讀取數(shù)據(jù)
data = pd.read_csv('movie_metadata.csv')
# print(' 數(shù)據(jù)的形狀 :', data.shape)
print(data.head())
# 2、處理缺失值
data = data.dropna(how='any') # print(data.head())
# 查看票房收入統(tǒng)計
# 導演vs票房總收入
group_director = data.groupby(by='director_name')['gross'].sum()
# ascending升降序排列,True升序
result = group_director.sort_values()
print(type(result))
print(result[])
# 電影產(chǎn)量年份趨勢
from matplotlib
import pyplot as plt
import random
from matplotlib import font_manager
movie_years = data.groupby('title_year')['movie_title'] print(movie_years.count().index.tolist()) print(movie_years.count().values)
x = movie_years.count().index.tolist()
y = movie_years.count().values
plt.figure(figsize=(20,8),dpi=80)
plt.plot(x,y)
plt.show()
之前忘了提醒大家,由于 Jupiter Notebook 的操作特點,基本是幾行代碼甚至一行代碼寫完就要看一下運行效果,所以有大量的代碼處在注釋狀態(tài),是為了不對正在執(zhí)行的代碼形成干擾。大家在練習的時候可以根據(jù)自己的需要對特定內(nèi)容取消注釋進行練習。注釋和取消注釋的快捷鍵沒忘吧?Ctrl+ /。
同樣的,想要練習的同學可以找我要筆記中提到的數(shù)據(jù)源文件哈~
那今天就到這兒啦~周二見!