天天看點

python中的df是什麼意思_python df周遊的N種方式

版權聲明:本文為部落客原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結和本聲明。

for…in 疊代循環首先介紹Python中最常用的for…in循環周遊的方式。for…in循環結構用于周遊清單、元組、字典、字元串、集合、檔案等。其實for和in是兩個獨立的文法,for語句是Python内置的疊代器工具,用于從可疊代容器對象(如清單、元組、字典、字元串、集合、檔案等)中逐個讀取元素,直到容器中沒有更多元素為止,工具和對象之間隻要遵循可疊代協定即可進行疊代操作。in的存在使得python在操作可疊代對象時變得簡單得多,用于配合for使用逐個取可疊代對象的元素。

for語句參與的具體疊代的過程為:可疊代對象通過iter方法傳回疊代器,疊代器具有next方法,for循環不斷地調用next方法,每次按序傳回疊代器中的一個值,直到疊代到最後,沒有更多元素時抛出異常StopIteration(Python會自動處理異常)。模拟疊代的過程如下所示:# 疊代的過程

x = [1,2,3]

its = x.__iter__() #清單是可疊代對象,否則會提示不是疊代對象

print(its)

# 列印結果:

print(next(its)) # its包含此方法,說明its是疊代器

# 列印結果:

1

print(next(its))

# 列印結果:

2

print(next(its))

# 列印結果:

3

print(next(its))

# 列印結果:

Traceback (most recent call last):

File "", line 1, in

StopIteration

疊代的優點是無需把所有元素一次加載到記憶體中,可以在調用next方法時逐個傳回元素,避免出現記憶體空間不夠的情況。

使用for…in循環方式實作單均線突破政策。周遊全部交易日的收盤價數值和Ma20數值,将收盤價數值減去Ma20數值,并使用np.sign()取內插補點符号,當收盤價在Ma20上方時內插補點為正,收盤價在Ma20上下方時內插補點為負,由負轉正對應為買點,由正轉負對應為賣點。如下所示def forin_looping(df):

df['signal'] = 0 #df = df.assign(signal = 0) #可采用assign新增一列

for i in np.arange(0,df.shape[0]):

df.iloc[i,df.columns.get_loc('signal')] = np.sign(df.iloc[i]['Close'] - df.iloc[i]['Ma20'])

return df

print(forin_looping(df_stockload)[0:5])

"""

High Low Open Close Volume Adj Close Ma20 signal

Date

2018-01-29 3587.0 3510.3 3563.6 3523.0 236000 3523.0 3454.3 1.0

2018-01-30 3523.1 3484.7 3511.5 3488.0 186400 3488.0 3461.3 1.0

2018-01-31 3495.5 3454.7 3470.5 3480.8 207300 3480.8 3466.8 1.0

2018-02-01 3495.1 3424.4 3478.7 3447.0 260500 3447.0 3469.9 -1.0

2018-02-02 3463.2 3388.9 3419.2 3462.1 208100 3462.1 3473.4 -1.0

"""

iterrows()生成器方式

另一種Python中常用的周遊方式為iterrows()生成器方式。所謂生成器其實是一種特殊的疊代器,内部支援了疊代器協定。Python中提供生成器函數和生成器表達式兩種方式實作生成器,每次請求傳回一個結果,不需要一次性建構一個結果清單,節省了記憶體空間。

在Python 3中可使用range傳回一個疊代器,用來一次一個值地周遊一個範圍.# 生成器函數方式實作生成器

def gensquares(N):

for i in range(N):

yield i**2

print(gensquares(5))

#列印結果:

for i in gensquares(5):

print(i)

# 列印結果:

1

4

9

16

其實yield就相當于一個return,隻是return傳回的是值,但是yield傳回的是生成器,除了這點其他都一樣,是以return也好yield也好都隻能用在函數中。

生成器表達式方式實作生成器就是類似清單解析,按需産生結果的一個對象,例程代碼如下所示:# 生成器表達式方式實作生成器

print(x**2 for x in range(5))

# 列印結果:

at 0xb3d31fa4>

print(list(x**2 for x in range(5)))

# 列印結果:

[0, 1, 4, 9, 16]

通過iterrows()周遊方式計算股票每個交易日收盤價與Ma20內插補點,此處iterrows是對dataframe格式資料行進行疊代的一個生成器,它傳回每行的索引及包含行本身的對象,代碼如下所示:#iterrows()周遊方式

def iterrows_loopiter(df):

df['signal'] = 0 #df = df.assign(signal = 0) #可采用assign新增一列

for index,row in df.iterrows():

df.loc[index, 'signal'] = np.sign(row['Close']-row['Ma20'])

return df

print(iterrows_loopiter(df_stockload)[0:5])

"""

High Low Open Close Volume Adj Close Ma20 signal

Date

2018-01-29 3587.0 3510.3 3563.6 3523.0 236000 3523.0 3454.3 1.0

2018-01-30 3523.1 3484.7 3511.5 3488.0 186400 3488.0 3461.3 1.0

2018-01-31 3495.5 3454.7 3470.5 3480.8 207300 3480.8 3466.8 1.0

2018-02-01 3495.1 3424.4 3478.7 3447.0 260500 3447.0 3469.9 -1.0

2018-02-02 3463.2 3388.9 3419.2 3462.1 208100 3462.1 3473.4 -1.0

"""

apply()循環方式

apply()方法可将函數應用于dataframe特定行或列。函數由lambda方式在代碼中内嵌實作,lambda 為匿名函數,可以省去定義函數的過程,讓代碼更加精簡。lambda函數的末尾包含axis參數,用來告知Pandas将函數運用于行(axis = 1)或者列(axis = 0)。apply()方法循環方式實作的代碼如下所示:df_stockload['signal'] = df_stockload.apply(lambda row: (np.sign(row['Close']-row['Ma20'])), axis = 1)

print(df_stockload.head())

"""

High Low Open Close Volume Adj Close Ma20 signal

Date

2018-01-29 3587.0 3510.3 3563.6 3523.0 236000 3523.0 3454.3 1.0

2018-01-30 3523.1 3484.7 3511.5 3488.0 186400 3488.0 3461.3 1.0

2018-01-31 3495.5 3454.7 3470.5 3480.8 207300 3480.8 3466.8 1.0

2018-02-01 3495.1 3424.4 3478.7 3447.0 260500 3447.0 3469.9 -1.0

2018-02-02 3463.2 3388.9 3419.2 3462.1 208100 3462.1 3473.4 -1.0

矢量化周遊方式

此處我們主要處理一維數組之間的計算,那麼矢量化方式可使用Pandas series 的矢量化方式和Numpy arrays的矢量化方式兩種。

先來看下Pandas series 的矢量化方式。

Pandas的DataFrame、series基礎單中繼資料結構基于連結清單,是以可将函數在整個連結清單上進行矢量化操作,而不用按順序執行每個值。

Pandas包括了非常豐富的矢量化函數庫,我們可把整個series(列)作為參數傳遞,對整個連結清單進行計算。Pandas series 的矢量化方式實作代碼如下:#Pandas series 的矢量化方式

df_stockload['signal'] = np.sign(df_stockload['Close']-df_stockload['Ma20'])

print(df_stockload.head())

"""

High Low Open Close Volume Adj Close Ma20 signal

Date

2018-01-29 3587.0 3510.3 3563.6 3523.0 236000 3523.0 3454.3 1.0

2018-01-30 3523.1 3484.7 3511.5 3488.0 186400 3488.0 3461.3 1.0

2018-01-31 3495.5 3454.7 3470.5 3480.8 207300 3480.8 3466.8 1.0

2018-02-01 3495.1 3424.4 3478.7 3447.0 260500 3447.0 3469.9 -1.0

2018-02-02 3463.2 3388.9 3419.2 3462.1 208100 3462.1 3473.4 -1.0

"""

對于Numpy arrays的矢量化方式,由于本例的矢量化運算中隻使用了series的數值,無需使用索引等資訊,是以可将series轉換為array類型,節省操作過程中的很多開銷。

我們可使用values 方法将連結清單從Pandas series轉換為NumPy arrays,把NumPy array作為參數傳遞,對整個連結清單進行計算。Numpy arrays的矢量化方式實作代碼如下:#Numpy arrays的矢量化方式

df_stockload['signal'] = np.sign(df_stockload['Close'].values-df_stockload['Ma20'].values)

print(df_stockload.head())

"""

High Low Open Close Volume Adj Close Ma20 signal

Date

2018-01-29 3587.0 3510.3 3563.6 3523.0 236000 3523.0 3454.3 1.0

2018-01-30 3523.1 3484.7 3511.5 3488.0 186400 3488.0 3461.3 1.0

2018-01-31 3495.5 3454.7 3470.5 3480.8 207300 3480.8 3466.8 1.0

2018-02-01 3495.1 3424.4 3478.7 3447.0 260500 3447.0 3469.9 -1.0

2018-02-02 3463.2 3388.9 3419.2 3462.1 208100 3462.1 3473.4 -1.0

"""

執行效率對比#使用timeit方法對比方法參考例程如下,需要import timeit子產品:

from timeit import timeit

def test1():

forin_looping(df_stockload)

def test2():

iterrows_loopiter(df_stockload)

def test3():

df_stockload['signal'] = df_stockload.apply(lambda row: (np.sign(row['Close'] - row['Ma20'])), axis=1)

def test4():

df_stockload['signal'] = np.sign(df_stockload['Close']-df_stockload['Ma20'])

def test5():

df_stockload['signal'] = np.sign(df_stockload['Close'].values - df_stockload['Ma20'].values)

#for..in循環疊代方式

t1 = timeit('test1()', 'from __main__ import test1', number=100)

#iterrows()周遊方式

t2 = timeit('test2()', 'from __main__ import test2', number=100)

#apply()方法循環方式

t3 = timeit('test3()', 'from __main__ import test3', number=100)

#Pandas series 的矢量化方式

t4 = timeit('test4()', 'from __main__ import test4', number=100)

#Numpy arrays的矢量化方式:

t5 = timeit('test5()', 'from __main__ import test5', number=100)

print(t1,t2,t3,t4,t5)

#14.943237108999998 8.827773373 0.5511996379999999 0.02215727200000117 0.012933490000001768

總結

可以看出循環執行的速度是最慢的,iterrows()針對Pandas的dataframe進行了優化,相比直接循環有顯著提升。apply()方法也是在行之間進行循環,但由于利用了類似Cython的疊代器的一系列全局優化,其效率要比iterrows高很多。

NumPy arrays的矢量化運作速度最快,其次是Pandas series矢量化。

由于矢量化是同時作用于整個序列的,可以節省更多的時間,相比使用标量操作更好,NumPy使用預編譯的C代碼在底層進行優化,同時也避免了Pandas series操作過程中的很多開銷,例如索引、資料類型等等,是以,NumPy arrays的操作要比Pandas series快得多。