1. 程式人生 > 其它 >雲原生的彈性 AI 訓練系列之二:PyTorch 1.9.0 彈性分散式訓練的設計與實現

雲原生的彈性 AI 訓練系列之二:PyTorch 1.9.0 彈性分散式訓練的設計與實現

摘要: Pandas學習筆記,摘自各種官方文件

Pandas

Pandas的命名來自於面板資料這個概念,即Panel datas

一些注意事項

axis 的軸向,主要看延展的方向,比如說有個矩陣AB,你想把他們上下合併,雖然看起來是一行行的在加,但是它實際的延展方向是豎著的,所以是axis=0,

**axis = 0 豎著合併 **

**axis = 1 橫著合併 **

shape = (3,4) 上下合併,之後axis = 0. 結果的話變成了shape = (6,4)

shape = (2,3,4) 第二維合併,之後axis=1,結果的話變成了shape = (2,6,4)

實訓課一、DataFrame初始化

0. 利用字典建立

data={"one":np.random.randn(4),"two":np.linspace(1,4,4),"three":['zhangsan','李四',999,0.1]}
df=pd.DataFrame(data,index=[1,2,3,4])
set _index用於將df中的一行或多行設定為索引。
df.set_index(['one'],drop=False)
df.set_index(['one','two'])
引數drop預設為True,意為將該列設定為索引後從資料中刪除,如果設為False,將繼續在資料中保留該行。

如果要設定的索引不在資料中,可以df.index=['a','b','c','d']
df.reset_index(drop=True)
引數drop預設值為False,意為將原來的索引做為資料列保留,如果設為True,原來的索引會直接刪除。

02 利用陣列建立

data=np.random.randn(6,4)#建立一個6行4列的陣列
df=pd.DataFrame(data,columns=list('ABCD'),index=[1,2,'a','b','2006-10-1','第六行'])

03 建立一個空DataFrame

pd.DataFrame(columns=('id','name','grade','class'))

實訓課二、DataFrame的級聯and合併操作

匹配級聯 concat, append——直接拼接兩個表

df1 = DataFrame(data=np.random.randint(0,100,size=(4,3)),columns=['A','B','C'])
df2 = DataFrame(data=np.random.randint(0,100,size=(4,4)),columns=['A','B','C','D'])
pd.concat((df1,df1),axis=0) #豎著合併df1,df1
pd.concat((df1,df2),axis=0) #豎著合併df1,df2 不存在的資料填充NaN,預設outer
pd.concat((df1,df2),axis=0,join='inner') #豎著合併df1,df2,不存在的那一列直接刪掉
df1.append(df2) #預設豎著合併兩個表,若無法對應則填Nan,預設outer

合併操作 merge ——通過某一列將兩個表連線起來

一對一合併

#df1,df2共有employee這個屬性,且每個屬性均只出現有且只有一次
pd.merge(df1,df2,on='employee')  #通過'employee'這個表連線兩個表

一對多合併

#df3,df4共有group這個屬性,會把group屬性相同的所有行進行全連線,也就是若df3的group的Accounting屬性有3個,df4的Accounting屬性有2個,最終表的Accounting屬性有6個
pd.merge(df3,df4,on='group')

多對多連線

#df1,df5,有一列有相同的屬性,然後左連線是,左邊那個表全部保留,遍歷右邊的表,若存在與之對應的,則新表增加一行,若不存在,則將不存在的屬性賦值為Nan
pd.merge(df1,df5,how='right')
pd.merge(df1,df5,how='left')

當兩張表沒有可進行連線的列時,可使用left_on和right_on手動指定merge中左右兩邊的哪一列列作為連線的列

pd.merge(df1,df5,left_on='employee',right_on='name')  #左表的employee和右表的name進行連線

實訓課三、高階操作

替換 replace

df.replace(to_replace=0,value='zero')   #把0值全部替換成zero
df.replace(to_replace={5:'five'})		#把5值全部替換成five
df.replace(to_replace={2:6,3:5},value='five') #把第2列的6和第3列的5全部變成five

對映 map

dic = {
    'zhangsan':"jay",
    'lisi':'tom',
    'wangwu1':'jerry'
}
df['e_name'] = df['name'].map(dic)  #dic是字典


def after_sal(s):
    return s-(s-3000)*0.5
df['after_sal'] = df['salary'].map(after_sal) #這裡的map可以寫成apply,apply遠比map高

隨機抽樣 take, permutation

df = pd.DataFrame(data=np.random.random(size=(100,4)),columns=['A','B','C','D'])  #隨機生成100*4
df.take(indices=np.random.permutation(4),axis=1) #0行,1列 把列隨機替換
df.take(indices=np.random.permutation(4),axis=1).take(indices=np.random.permutation(100),axis=0)[:20] #先列隨機,再行隨機,再取前20個

資料分組聚合

df = pd.DataFrame({'item':['Apple','Banana','Orange','Banana','Orange','Apple'],
                'price':[4,3,3,2.5,4,2],
               'color':['red','yellow','yellow','green','green','green'],
               'weight':[12,20,50,30,20,44]})


df.groupby(by='item').groups #groups返回分組結果
df.groupby(by='item').mean() #mean聚合操作只會對數值型的資料進行聚合
df.groupby(by='item').mean()['price'] #先分組、聚合,再提取某列
df.groupby(by='item')['price'].mean() #先分組、提取某列,再聚合

dic = mean_price_s.to_dict()	#series轉字典
df['mean_price'] = df['item'].map(dic) #字典再映射回去

def myMean(p):
    sum = 0
    for i in p:
        sum += i
    return sum / len(p)
#transform 有多少行返回多少行,分組之後,每個值都會代回去原來那行
df.groupby(by='item')['price'].transform(myMean)
#apply 返回分組的結果,如果需要代回去,還需要變成dict 然後 map。不如直接transform
df.groupby(by='item')['price'].apply(myMean)

透視表

透視表像是直接幫你分組

#直接將對手和主客場做一個分組,預設求均值,然後有三列
df.pivot_table(index=['主客場','勝負'],values=['得分','籃板','助攻'])
df.pivot_table(index=['主客場','勝負'],values=['得分','籃板','助攻'],aggfunc='sum')	# 全做求和
df.pivot_table(index=['主客場','勝負'],aggfunc={'得分':'sum','籃板':'max'}) 			  #得分求和,籃板求最大值

#獲取所有隊主客場的總得分
df.pivot_table(index=['主客場'],values='得分',aggfunc='sum')
#檢視主客場下的總得分的貢獻各是多少
df.pivot_table(index=['主客場'],values='得分',aggfunc='sum',columns='對手',fill_value=0)

交叉表

#交叉表更像是,給定index 和 column,然後彙總

pd.crosstab(index=df.smoke,columns=df.sex) 	#求出各個性別抽菸的人數
pd.crosstab(df.age,df.smoke)				#求出各個年齡段抽菸人情況

一、引入模組

將pandas作為第三方庫匯入,我們一般為pandas取一個別名叫做pd

import pandas as pd 

二、匯入資料

df = pd.read_csv(
    # 該引數為資料在電腦中的路徑,可以不填寫
    filepath_or_buffer='/Users/Weidu/Desktop/sz000002.csv',
    # 該引數代表資料的分隔符,csv檔案預設是逗號。其他常見的是'\t'
    sep=',',
    # 該引數代表跳過資料檔案的的第1行不讀入
    skiprows=1,
    # nrows,只讀取前n行資料,若不指定,讀入全部的資料
    nrows=15,
    # 將指定列的資料識別為日期格式。若不指定,時間資料將會以字串形式讀入。一開始先不用。
    # parse_dates=['交易日期'],
    # 將指定列設定為index。若不指定,index預設為0, 1, 2, 3, 4...
    # index_col=['交易日期'],
    # 讀取指定的這幾列資料,其他資料不讀取。若不指定,讀入全部列
    usecols=['交易日期', '股票程式碼', '股票名稱', '收盤價', '漲跌幅', '成交量', '新浪概念', 'MACD_金叉死叉'],
    # 當某行資料有問題時,報錯。設定為False時即不報錯,直接跳過該行。當資料比較髒亂的時候用這個。
    error_bad_lines=False,
    # 將資料中的null識別為空值
    na_values='NULL',
)

三、檢視資料常用操作

print(df.shape) 	# 輸出dataframe有多少行、多少列。
print(df.shape[0])	# 取行數量,相應的列數量就是df.shape[1]
print(df.columns) 	# 順序輸出每一列的名字,演示如何for語句遍歷。
print(df.index) 	# 順序輸出每一行的名字,可以for語句遍歷。
print(df.dtypes) 	# 資料每一列的型別不一樣,比如數字、字串、日期等。該方法輸出每一列變數型別
print(df.head(3))  	# 看前3行的資料,預設是5。與自然語言很接近
print(df.tail(3))  	# 看最後3行的資料,預設是5。
print(df.sample(n=3)) 	# 隨機抽取3行,想要去固定比例的話,可以用frac引數
print(df.describe()) 	# 非常方便的函式,對每一列資料有直觀感受;只會對數字型別的列有效

四、DataFrame太大,輸出修正

pd.set_option('expand_frame_repr', False)  	# 當列太多時不換行
pd.set_option('max_colwidth', 8) 			
# 設定每一列的最大寬度,恢復原設定的方法,pd.reset_option('max_colwidth')

五、選取指定列

df['股票程式碼']  			  #根據列名稱來選取,讀取的資料是Series型別
df[['股票程式碼', '收盤價']]		#同時選取多列,需要兩個括號,讀取的資料是DataFrame型別
df[[0, 1, 2]]  				 #也可以通過列的position來選取

六、loc操作 顯式索引讀取資料

df.loc['12/12/2016'] 				# 選取指定的某一行,讀取的資料是Series型別
df.loc['13/12/2016': '06/12/2016']  # 選取在此範圍內的多行,和在list中slice操作類似,讀取的資料是DataFrame型別

df.loc[:, '股票程式碼':'收盤價'] 		# 選取在此範圍內的多列,讀取的資料是DataFrame型別
df.loc['13/12/2016': '06/12/2016', '股票程式碼':'收盤價']  
									# 讀取指定的多行、多列。逗號之前是行的範圍,逗號之後是列的範圍。讀取的資料是DataFrame型別

df.loc[:, :]  						 # 讀取所有行、所有列,讀取的資料是DataFrame型別
df.at['12/12/2016', '股票程式碼']  	  # 使用at讀取指定的某個元素。loc也行,但是at更高效。

七、iloc操作 隱式索引讀取資料

df.iloc[0] 			# 以index選取某一行,讀取的資料是Series型別
df.iloc[1:3] 		# 選取在此範圍內的多行,讀取的資料是DataFrame型別
df.iloc[:, 1:3] 	# 選取在此範圍內的多列,讀取的資料是DataFrame型別
df.iloc[1:3, 1:3]  	# 讀取指定的多行、多列,讀取的資料是DataFrame型別
df.iloc[:, :]  		# 讀取所有行、所有列,讀取的資料是DataFrame型別
df.iat[1, 1]  		# 使用iat讀取指定的某個元素。使用iloc也行,但是iat更高效。

八、增加列,列運算

行列加減乘除

print(df['股票名稱'] + '_地產')  	  # 字串列可以直接加上字串,對整列進行操作
print(df['收盤價'] * 100)  	    # 數字列直接加上或者乘以數字,對整列進行操作。
print(df['收盤價'] * df['成交量'])  # 兩列之間可以直接操作。收盤價*成交量計算出的是什麼?

新增一列

df['股票名稱+行業'] = df['股票名稱'] + '_地產'

九、統計函式,計量函式

print(df['收盤價'].mean())  	# 求一整列的均值,返回一個數。會自動排除空值。
print(df['收盤價'].max())  	# 最大值
print(df['收盤價'].min())  	# 最小值
print(df['收盤價'].std())  	# 標準差
print(df['收盤價'].count())  	# 非空的資料的數量
print(df['收盤價'].median())  	# 中位數
print(df['收盤價'].quantile(0.25))  # 25%分位數

十、shift類函式、刪除列的方式

df['昨天收盤價'] = df['收盤價'].shift(-1)  # 讀取上一行的資料,若引數設定為3,就是讀取上三行的資料;若引數設定為-1,就是讀取下一行的資料;

df['漲跌'] = df['收盤價'].diff(-1)  # 求本行資料和上一行資料相減得到的值

df.drop(['漲跌'], axis=1, inplace=True)  # 刪除某一列

df['漲跌幅_計算'] = df['收盤價'].pct_change(-1)  # 類似於diff,但是求的是兩個數直接的比例,相當於求漲跌幅

十一、cum(cumulative)類函式

df['成交量_cum'] = df['成交量'].cumsum()  # 該列的累加值
df[['成交量', '成交量_cum']]
(df['漲跌幅'] + 1.0).cumprod()  # 該列的累乘值,此處計算的就是資金曲線,假設初始1元錢。

十二、其他列函式rank,value_counts

df['收盤價_排名'] = df['收盤價'].rank(ascending=True, pct=False)  # 輸出排名。ascending引數代表是順序還是逆序。pct引數代表輸出的是排名還是排名比例

print(df['股票程式碼'].value_counts())  # 計數。統計該列中每個元素出現的次數。返回的資料是Series

十三、篩選操作,根據指定的條件,篩選出相關拿資料

#dataFrame 可以通過布林矩陣來選中值,所以就很帥。
s1 = df['ma5'] < df['ma30']
s2 = df['ma5'] > df['ma30']
death_dt = df.loc[s1 & s2.shift(1)].index 		#死叉
golden_dt = df.loc[~(s1 | s2.shift(1))].index	#金叉

十四、缺失值處理:原始資料中存在缺失值,如何處理?

查詢缺失值

df.isnull().any(axis=1) 	#any可以檢測df中的true和false的分佈,如果行/列中只要存在一個true,則any就會返回true   這裡返回布林矩陣,對於每一行,只要存在一個True,則返回True,大小是行數

df.isnull()		#空則True
df.notnull()	#非空則True
df.notnull().all(axis=1)	#對每一行,若全部非空,則True
df.isnull().any(axis=1)		#對每一行,若存在一個非空,則True

df.dropna(axis=0) 		#刪除空值所在行
df.fillna(value=666)	#空值填充666
df.fillna(axis=1,method='bfill') #空值用行的方式,用後一個填充前面的

df.isnull().any(axis=1).sum() 	#求和看看有多少行是存在空值的

for col in df.columns:			#迴圈把每個空值填充為該列的平均值
    if df[col].isnull().sum() > 0:
        #df[col]列中存在空值
        mean_value = df[col].mean()
        df[col].fillna(value=mean_value,inplace=True)

十五、排序函式

df.reset_index(inplace=True)
df.sort_values(by=['交易日期'], ascending=1)  # by引數指定按照什麼進行排序,acsending引數指定是順序還是逆序,1順序,0逆序
df.sort_values(by=['股票名稱', '交易日期'], ascending=[1, 1])  # 按照多列進行排序

十六、兩個df上下合併操作,append操作

df.reset_index(inplace=True)
df1 = df.iloc[0:10][['交易日期', '股票程式碼', '收盤價', '漲跌幅']]
df2 = df.iloc[5:15][['交易日期', '股票名稱', '收盤價', '漲跌幅']]

df1.append(df2)
df3 = df1.append(df2, ignore_index=True)  # ignore_index引數,使用者重新確定index

十七、對資料進行去重drop_duplicates

#df3中有重複的行數,我們如何將重複的行數去除?
df3.drop_duplicates(
    subset=['收盤價', '交易日期'],  # subset引數用來指定根據哪類類資料來判斷是否重複。若不指定,則用全部列的資料來判斷是否重複
    keep='first',  # 在去除重複值的時候,我們是保留上面一行還是下面一行?first保留上面一行,last保留下面一行,False就是一行都不保留
    inplace=True
)

十八、其他常用重要函式 rename, empty, T轉置

print(df.rename(columns={'MACD_金叉死叉': '金叉死叉', '漲跌幅': '漲幅'}))  # rename函式給變數修改名字。使用dict將要修改的名字傳給columns引數
print(df.empty)  # 判斷一個df是不是為空,此處輸出不為空
print(pd.DataFrame().empty)  # pd.DataFrame()建立一個空的DataFrame,此處輸出為空
print(df.T)  # 將資料轉置,行變成列,很有用

十九、字串處理

print(df['股票程式碼'])
print('sz000002'[:2])
print(df['股票程式碼'].str[:2])
print(df['股票程式碼'].str.upper())  # 加上str之後可以使用常見的字串函式對整列進行操作
print(df['股票程式碼'].str.lower())
print(df['股票程式碼'].str.len())  # 計算字串的長度,length
df['股票程式碼'].str.strip()  # strip操作,把字串兩邊的空格去掉
print(df['股票程式碼'].str.contains('sh'))  # 判斷字串中是否包含某些特定字元
print(df['股票程式碼'].str.replace('sz', 'sh'))  # 進行替換,將sz替換成sh

split操作

print(df['新浪概念'].str.split(';'))  # 對字串進行分割
print(df['新浪概念'].str.split(';').str[:2])  # 分割後取第一個位置
print(df['新浪概念'].str.split(';', expand=True))  # 分割後並且將資料分列

二十、時間處理

匯入資料時將index引數註釋掉
df['交易日期'] = pd.to_datetime(df['交易日期'])  # 將交易日期由字串改為時間變數
print(df['交易日期'])
print(df.iloc[0]['交易日期'])
print(df.dtypes)
print(pd.to_datetime('1999年01月01日')) # pd.to_datetime函式:將字串轉變為時間變數
print(df.at[0, '交易日期'])
print(df['交易日期'].dt.year)  # 輸出這個日期的年份。相應的month是月份,day是天數,還有hour, minute, second
print(df['交易日期'].dt.week)  # 這一天是一年當中的第幾周
print(df['交易日期'].dt.dayofyear)  # 這一天是一年當中的第幾天
print(df['交易日期'].dt.dayofweek) # 這一天是這一週當中的第幾天,0代表星期一
print(df['交易日期'].dt.weekday)  # 和上面函式相同,更加常用
print(df['交易日期'].dt.weekday_name)  # 和上面函式相同,返回的是星期幾的英文,用於報表的製作。
print(df['交易日期'].dt.days_in_month)  # 這一天是這一月當中的第幾天
print(df['交易日期'].dt.is_month_end)  # 這一天是否是該月的開頭,是否存在is_month_end?
print(df['交易日期'] + pd.Timedelta(days=1))  # 增加一天,Timedelta用於表示時間差資料
print((df['交易日期'] + pd.Timedelta(days=1)) - df['交易日期'])  # 增加一天然後再減去今天的日期

二十一、rolling、expanding操作

#計算'收盤價'這一列的均值
print(df['收盤價'].mean())

#如何得到每一天的最近3天收盤價的均值呢?即如何計算常用的移動平均線?
#使用rolling函式
df['收盤價_3天均值'] = df['收盤價'].rolling(5).mean()

#rolling(n)即為取最近n行資料的意思,只計算這n行資料。後面可以接各類計算函式,例如max、min、std等
print(df['收盤價'].rolling(3).max())
print(df['收盤價'].rolling(3).min())
print(df['收盤價'].rolling(3).std())

rolling可以計算每天的最近3天的均值,如果想計算每天的從一開始到至今為止的均值,應該如何計算?

#使用expanding操作
df['收盤價_至今均值'] = df['收盤價'].expanding().mean()

expanding即為取從頭至今的資料。後面可以接各類計算函式

print(df['收盤價'].expanding().max())
print(df['收盤價'].expanding().min())
print(df['收盤價'].expanding().std())

二十二、輸出

df.to_csv('output.csv', encoding='gbk', index=False)