1. 程式人生 > 其它 >Datawhale程式設計實踐(Pandas) Task02

Datawhale程式設計實踐(Pandas) Task02

技術標籤:datawhalepythonpandas

一、檔案的讀取和寫入

excelcsvtxt
檔案讀取pd.read_excel()pd.read_csv()pd.read_table()
資料寫入to_excel()to_csv()to_csv()

1. 檔案讀取

  • csv檔案讀取:pd.read_csv

pandas.read_csv(filepath_or_buffer, sep=’,’, delimiter=None, header=‘infer’, names=None, index_col=None, usecols=None, squeeze=False, prefix=None, mangle_dupe_cols=True, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skipinitialspace=False, skiprows=None, skipfooter=0, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=False, infer_datetime_format=False, keep_date_col=False, date_parser=None, dayfirst=False, cache_dates=True, iterator=False, chunksize=None, compression=‘infer’, thousands=None, decimal=’.’, lineterminator=None, quotechar=’"’, quoting=0, doublequote=True, escapechar=None, comment=None, encoding=None, dialect=None, error_bad_lines=True, warn_bad_lines=True, delim_whitespace=False, low_memory=True, memory_map=False, float_precision=None)

df_csv = pd.read_csv("Data/my_csv.csv")
df_csv

	col1	col2	col3	col4	col5
0	2		a		1.4		apple	2020/1/1
1	3		b		3.4		banana	2020/1/2
2	6		c		2.5		orange	2020/1/5
3	5		d		3.2		lemon	2020/1/7
  • txt檔案讀取:pd.read_table

pandas.read_table(filepath_or_buffer, sep=’\t’, delimiter=None, header=‘infer’, names=None, index_col=None, usecols=None, squeeze=False, prefix=None, mangle_dupe_cols=True, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skipinitialspace=False, skiprows=None, skipfooter=0, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=False, infer_datetime_format=False, keep_date_col=False, date_parser=None, dayfirst=False, cache_dates=True, iterator=False, chunksize=None, compression=‘infer’, thousands=None, decimal=’.’, lineterminator=None, quotechar=’"’, quoting=0, doublequote=True, escapechar=None, comment=None, encoding=None, dialect=None, error_bad_lines=True, warn_bad_lines=True, delim_whitespace=False, low_memory=True, memory_map=False, float_precision=None)

df_txt = pd.read_table('data/my_table.txt')
df_txt


	col1	col2	col3	col4
0	2		a		1.4		apple 2020/1/1
1	3		b		3.4		banana 2020/1/2
2	6		c		2.5		orange 2020/1/5
3	5		d		3.2		lemon 2020/1/7
  • excel檔案讀取:pd.read_excel

pandas.read_excel(io, sheet_name=0, header=0, names=None, index_col=None, usecols=None, squeeze=False, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skiprows=None, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, parse_dates=False, date_parser=None, thousands=None, comment=None, skipfooter=0, convert_float=True, mangle_dupe_cols=True)

df_excel = pd.read_excel('data/my_excel.xlsx')
df_excel

	col1	col2	col3	col4	col5
0	2		a		1.4		apple	2020/1/1
1	3		b		3.4		banana	2020/1/2
2	6		c		2.5		orange	2020/1/5
3	5		d		3.2		lemon	2020/1/7
  • 公共引數:
型別引數定義
headerint, list of int, default 0指定作為列名的行,預設0,即取第一行,資料為列名行以下的資料;若資料不含列名,則設定 header = None;
index_colint, list of int, default None用作行索引的列編號或者列名,如果給定一個序列則有多個行索引
usecolsint, str, list-like, or callable default None返回一個數據子集,該列表中的值必須可以對應到檔案中的位置(數字可以對應到指定的列)或者是字元傳為檔案中的列名。
namesarray-like, default None指定列的名字,傳入一個list資料
skiprowslist-like省略指定行數的資料
skipfooterint, default 0省略從尾部數的行資料
  • 單獨引數
引數定義
sep指定分隔符。如果不指定引數,則會嘗試使用逗號分隔。引數 sep 中使用的是正則表示式,因此需要進行轉義,否則無法讀取到正確的結果。
pd.read_table('data/my_table_special_sep.txt')

	col1 |||| col2
0	TS |||| This is an apple.
1	GQ |||| My name is Bob.
2	WT |||| Well done!
3	PT |||| May I help you?
# 使用 read_table 的時候需要注意,引數 sep 中使用的是正則表示式,因此需要對 | 進行轉義變成 \| ,否則無法讀取到正確的結果。
# 指定引擎為 python,否則會出現警告
pd.read_table('data/my_table_special_sep.txt', sep = '\|\|\|\|', engine = 'python')

	col1	col2
0	TS		This is an apple.
1	GQ		My name is Bob.
2	WT		Well done!
3	PT		May I help you?

2. 檔案寫入

最常用的操作是把 index 設定為 False ,特別當索引沒有特殊意義的時候,這樣的行為能把索引在儲存的時候去除。

  • csv檔案 / txt檔案寫入

DataFrame.to_csv(path_or_buf=None, sep=’,’, na_rep=’’, float_format=None, columns=None, header=True, index=True, index_label=None, mode=‘w’, encoding=None, compression=‘infer’, quoting=None, quotechar=’"’, line_terminator=None, chunksize=None, date_format=None, doublequote=True, escapechar=None, decimal=’.’, errors=‘strict’)

  • excel檔案寫入

DataFrame.to_excel(excel_writer, sheet_name=‘Sheet1’, na_rep=’’, float_format=None, columns=None, header=True, index=True, index_label=None, startrow=0, startcol=0, engine=None, merge_cells=True, encoding=None, inf_rep=‘inf’, verbose=True, freeze_panes=None)

df_csv.to_csv('data/my_csv_saved.csv', index=False)
df_excel.to_excel('data/my_excel_saved.xlsx', index=False)
df_txt.to_csv('data/my_txt_saved.txt', sep='\t', index=False)

為什麼要轉化markdown語言,主要是為了方便儲存,且易於轉成其他格式,比如PDF,也能方便出版列印和交流傳播

to_markdown: 表格轉換為markdown語言
to_latex:可表格轉換為to_latex語言
沒有安裝tabulate包,要先pip install tabulate

二、基本資料結構

1. Series

# Series 一般由四個部分組成,分別是序列的值 data 、索引 index 、儲存型別 dtype 、序列的名字 name 。其中,索引也可以指定它的名字,預設為空。
s = pd.Series(data = [100, 'a', {'dic1':5}],
              index = pd.Index(['id1', 20, 'third'], name='my_idx'),
              dtype = 'object',
              name = 'my_name')
屬性
.values獲取序列的值
.index獲取索引
.dtype獲取儲存型別
.name獲取名字
.shape獲取序列的長度

2. DataFrame

DataFrame 在 Series 的基礎上增加了列索引,一個數據框可以由二維的 data 與行列索引來構造

data = [[1, 'a', 1.2], [2, 'b', 2.2], [3, 'c', 3.2]]
df = pd.DataFrame(data = data,
                  index = ['row_%d'%i for i in range(3)],
                  columns=['col_0', 'col_1', 'col_2'])

#更多的時候會採用從列索引名到資料的對映來構造資料框,同時再加上行索引
df = pd.DataFrame(data = {'col_0': [1,2,3], 'col_1':list('abc'),'col_2': [1.2, 2.2, 3.2]},
                  index = ['row_%d'%i for i in range(3)])

屬性與Series相同,轉置可以用.T,這點同numpy的用法

三、常用基本函式

1. 彙總函式

函式屬性
.head()返回表或者序列的前 n 行,預設為5
.tail()返回表或者序列的後n行,預設為5
.info()返回表的資訊概況
.describe()返回表中數值列對應的主要統計量

info, describe 只能實現較少資訊的展示,如果想要對一份資料集進行全面且有效的觀察,特別是在列較多的情況下,推薦使用 pandas-profiling 包。

df.head() #返回表或序列的前5行

		School							Grade		Name			Gender	Height	Weight	Transfer
0		Shanghai Jiao Tong University	Freshman	Gaopeng Yang	Female	158.9	46.0	N
1		Peking University				Freshman	Changqiang You	Male	166.5	70.0	N
2		Shanghai Jiao Tong University	Senior		Mei Sun			Male	188.9	89.0	N
3		Fudan University				Sophomore	Xiaojuan Sun	Female	NaN		41.0	N
4		Fudan University				Sophomore	Gaojuan You		Male	174.0	74.0	N
df.head(2) #返回表或序列的前2行

	School							Grade		Name			Gender	Height	Weight	Transfer
0	Shanghai Jiao Tong University	Freshman	Gaopeng Yang	Female	158.9	46.0	N
1	Peking University				Freshman	Changqiang You	Male	166.5	70.0	N
df.tail(1) #返回表或序列的最後1行

	School				Grade		Name		Gender	Height	Weight	Transfer
199	Tsinghua University	Sophomore	Chunpeng Lv	Male	155.7	51.0	N
df.info() #返回表的資訊概況

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 200 entries, 0 to 199
Data columns (total 7 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   School    200 non-null    object 
 1   Grade     200 non-null    object 
 2   Name      200 non-null    object 
 3   Gender    200 non-null    object 
 4   Height    183 non-null    float64
 5   Weight    189 non-null    float64
 6   Transfer  188 non-null    object 
dtypes: float64(2), object(5)
memory usage: 11.1+ KB
df.describe() #返回表中數值列對應的主要統計量

		Height		Weight
count	183.000000	189.000000
mean	163.218033	55.015873
std		8.608879	12.824294
min		145.400000	34.000000
25%		157.150000	46.000000
50%		161.900000	51.000000
75%		167.500000	65.000000
max		193.900000	89.000000

2. 特徵統計函式

函式屬性
.sum()求和
.mean()平均數
.median()中值
.var()方差
.std()標準差
.max()最大值
.min()最小值
.quantile()計算分位數,預設為50%分位數
.count()計算非缺失值的個數
.idxmax()返回最大值對應的索引
df_demo.sum() #求和

Height    29868.9
Weight    10398.0
dtype: float64
df_demo.mean() #平均數

Height    163.218033
Weight     55.015873
dtype: float64
df_demo.median() #求中值

Height    161.9
Weight     51.0
dtype: float64
df_demo.var() #計算方差

Height     74.112805
Weight    164.462513
dtype: float64
-----------------
df_demo.std() #計算標準差

Height     8.608879
Weight    12.824294
dtype: float64
df_demo.max() #計算最大值
Height    193.9
Weight     89.0
dtype: float64
-----------------
df_demo.min() #計算最小值
Height    145.4
Weight     34.0
dtype: float64
df_demo.quantile() #計算50%分位數
Height    161.9
Weight     51.0
Name: 0.5, dtype: float64
-----------------
df_demo.quantile(0.75) #計算75%分位數
Height    167.5
Weight     65.0
Name: 0.75, dtype: float64
df_demo.idxmax() #返回最大值對應的索引
Height    193
Weight      2
dtype: int64

上面這些所有的函式,由於操作後返回的是標量,所以又稱為聚合函式,它們有一個公共引數 axis,預設為0代表逐列聚合,如果設定為1則表示逐行聚合

df_demo.sum(axis = 1).head(3)
0    204.9
1    236.5
2    277.9
dtype: float64

3. 唯一值函式

函式屬性
.unique()返回其唯一值組成的列表
.nunique()返回唯一值的個數
.value_counts()返回唯一值和其對應出現的頻數
.drop_duplicates()返回多個列組合的唯一值,關鍵引數是keep,預設值first表示每個組合保留第一次出現的所在行,last表示保留最後一次出現的所在行,False表示把所有重複組合所在的行剔除。
.duplicated()返回是否為唯一值的布林列表,其中重複元素設為True,否則為False
df['Grade'].unique() #返回其唯一值組成的列表
>>> array(['Freshman', 'Senior', 'Sophomore', 'Junior'], dtype=object)
-----------------
df['Grade'].nunique() #返回其唯一值的個數
>>> 4
df['Grade'].value_counts() #返回唯一值和其對應出現的頻數
Junior       59
Senior       55
Freshman     52
Sophomore    34
Name: Grade, dtype: int64
df_demo.drop_duplicates(['Gender', 'Transfer']) #返回多個列組合的唯一值,預設keep=first,每個組合第一次出現的行

	Gender	Transfer	Name
0	Female	N			Gaopeng Yang
1	Male	N			Changqiang You
12	Female	NaN			Peng You
21	Male	NaN			Xiaopeng Shen
36	Male	Y			Xiaojuan Qin
43	Female	Y			Gaoli Feng
-----------------
df_demo.drop_duplicates(['Gender', 'Transfer'], keep = 'last') #返回多個列組合的唯一值,每個組合最後一次出現的行

	Gender	Transfer	Name
147	Male	NaN			Juan You
150	Male	Y			Chengpeng You
169	Female	Y			Chengquan Qin
194	Female	NaN			Yanmei Qian
197	Female	N			Chengqiang Chu
199	Male	N			Chunpeng Lv
-----------------
df_demo.drop_duplicates(['Name', 'Transfer'], keep = False).head(3) #返回不重複值

	Gender	Transfer	Name
0	Female	N			Gaopeng Yang
1	Male	N			Changqiang You
4	Male	N			Gaojuan You
df_demo.duplicated(['Gender', 'Transfer']).head() #返回是否為重複值的布林列表
0    False
1    False
2     True
3     True
4     True
dtype: bool

4. 替換函式

一般而言,替換操作是針對某一列,即 Series 進行。

分類函式屬性
對映替換.replace()可以通過字典構造,或者傳入兩個列表來進行替換;此外還有一種特殊的定向替換,指定method引數
對映替換.str.replace()字串替換,後見Task08
對映替換cat.codes通過reorder_categories進行重新排序,然後再使用cat.codes來實現對整數的對映(暫時沒明白與替換的關係,後改)
邏輯替換.where(條件, 返回值)在傳入條件為False的對應行進行替換,當不指定替換值時,替換為缺失值NaN
邏輯替換.mask()在傳入條件為True的對應行進行替換,當不指定替換值時,替換為缺失值NaN
數值替換.round()按照給定精度四捨五入
數值替換.abs()返回絕對值
數值替換Series.clip(lower=None, upper=None, axis=None, inplace=False, *args, **kwargs)按照給定上下界截斷,前兩個數分別表示上下截斷邊界
df['Gender'].replace({'Female':0, 'Male':1}).head() #通過字典構造替換
0    0
1    1
2    1
3    0
4    1
Name: Gender, dtype: int64
-----------------
df['Gender'].replace(['Female','Male'],[0,1]).head() #通過傳入兩個列表來進行替換
0    0
1    1
2    1
3    0
4    1
Name: Gender, dtype: int64
s.replace([1, 2], method='ffill') #一種特殊的定向替換,返回上一個未被替換的值
0    a
1    a
2    b
3    b
4    b
5    a
dtype: object
-----------------
s.replace([1, 2], method='bfill') #一種特殊的定向替換,返回下一個未被替換的值
0    a
1    b
2    b
3    a
4    a
5    a
dtype: object
s.where(s<0) #替換s>=0的值,替換為缺失值
0    -1.0
1     NaN
2     NaN
3   -50.0
dtype: float64
-----------------
s.where(s<0, 50) #替換s>=0的值,替換為50
0    -1.0
1    50.0
2    50.0
3   -50.0
dtype: float64
-----------------
s.mask(s>=0) #替換s>=0的值,替換為缺失值
0    -1.0
1     NaN
2     NaN
3   -50.0
dtype: float64
-----------------
s.mask(s>=0, 100) #替換s>=0的值,替換為100
0     -1.0
1    100.0
2    100.0
3    -50.0
dtype: float64
s.round(2) #四捨五入到兩位小數
0     -1.00
1      1.23
2    100.00
3    -50.00
dtype: float64

s.abs() #返回絕對值
0      1.0000
1      1.2345
2    100.0000
3     50.0000
dtype: float64

s.clip(0, 2) #截斷0-2邊界外的數
0    0.0000
1    1.2345
2    2.0000
3    0.0000
dtype: float64

練一練:
在 clip 中,超過邊界的只能截斷為邊界值,如果要把超出邊界的替換為自定義的值,應當如何做?

#思考:可以使用replace代替上界和下界
a = 0
b = 2
s.clip(a, b).replace({a:'lower', b:'upper'})

0     lower
1    1.2345
2     upper
3     lower
dtype: object

5. 排序函式

函式引數
.sort_values()為值排序,預設引數 ascending=True 為升序
.sort_index()為索引排序,需要指定索引層的名字或者層號,用引數 level 表示
df_demo = df[['Grade', 'Name', 'Height', 'Weight']].set_index(['Grade','Name'])
df_demo.sort_values('Height').head() #按照身高升序排列,顯示前5行

							Height	Weight
Grade		Name		
Junior		Xiaoli Chu		145.4	34.0
Senior		Gaomei Lv		147.3	34.0
Sophomore	Peng Han		147.8	34.0
Senior		Changli Lv		148.7	41.0
Sophomore	Changjuan You	150.5	40.0
-----------------
df_demo.sort_values('Height', ascending = False).head(3) #按照身高降序排列,顯示前3行

						Height	Weight
Grade	Name		
Senior	Xiaoqiang Qin	193.9	79.0
		Mei Sun			188.9	89.0
		Gaoli Zhao		186.5	83.0
-----------------
df_demo.sort_values(['Height', 'Weight'], ascending = [False, True]).head() #按照身高降序,體重升序排列

							Height	Weight
Grade		Name		
Senior		Xiaoqiang Qin	193.9	79.0
			Mei Sun			188.9	89.0
			Gaoli Zhao		186.5	83.0
Freshman	Qiang Han		185.3	87.0
Senior		Qiang Zheng		183.9	87.0
df_demo.sort_index(level=['Grade','Name'],ascending=[True,False]).head() #按照年級升序,名字降序排列

							Height	Weight
Grade		Name		
Freshman	Yanquan Wang	163.5	55.0
			Yanqiang Xu		152.4	38.0
			Yanqiang Feng	162.3	51.0
			Yanpeng Lv		NaN		65.0
			Yanli Zhang		165.1	52.0

6. apply方法

得益於傳入自定義函式的處理, apply 的自由度很高,但這是以效能為代價的。一般而言,使用 pandas 的內建函式處理和 apply 來處理同一個任務,其速度會相差較多,因此只有在確實存在自定義需求的情境下才考慮使用 apply 。

#處理自定義函式,例如: mad 函式返回的是一個序列中偏離該序列均值的絕對值大小的均值
df_demo = df[['Height', 'Weight']]
df_demo.apply(lambda x:(x-x.mean()).abs().mean())

Height     6.707229
Weight    10.391870
dtype: float64

四、視窗物件

函式屬性
滑動視窗rolling引數為視窗大小window
擴張視窗expandingSeries.expanding(min_periods=1, center=None, axis=0)
指數加權視窗ewm

1. 滑動視窗

需要注意的是視窗包含當前行所在的元素

s = pd.Series([1,2,3,4,5])
roller = s.rolling(window = 2)
roller.sum()

0    NaN
1    3.0
2    5.0
3    7.0
4    9.0
dtype: float64
-----------------
roller.apply(lambda x:x.sum()) #等價表示
類滑窗函式屬性
.shift(n)引數為 periods=n ,預設為1,表示取向前第 n 個元素的值
.diff(n)引數為 periods=n ,預設為1,表示與向前第 n 個元素做差
.pct_change(n)引數為 periods=n ,預設為1,與向前第 n 個元素相比計算增長率
s.shift(2) #取向前的第2個元素的值,即series向後移動2位

0    NaN
1    NaN
2    1.0
3    3.0
4    6.0
dtype: float64
-----------------
s.diff(2) #與向前第2個元素做差

0    NaN
1    NaN
2    5.0
3    7.0
4    9.0
dtype: float64
-----------------
s.pct_change() #與前1個元素的增長率

0         NaN
1    2.000000
2    1.000000
3    0.666667
4    0.500000
dtype: float64

n 可以為負,表示反方向的類似操作:

s.shift(-1) #取後一個元素的值

0     3.0
1     6.0
2    10.0
3    15.0
4     NaN
dtype: float64

類滑窗函式的功能可以用視窗大小為 n+1 的 rolling 方法等價代替:

s.rolling(3).apply(lambda x:list(x)[0]) #等價於s.shift(2)

練一練:
rolling 物件的預設視窗方向都是向前的,某些情況下使用者需要向後的視窗,例如對1,2,3設定向後窗口為2的 sum 操作,結果為3,5,NaN,此時應該如何實現向後的滑窗操作?

s = pd.Series([1, 2, 3])
#Step1:嘗試使用window引數,報錯:window必須為正整數
roller = s.rolling(window = -1)
ValueError: window must be non-negative

#Step2:先試用rolling求和,再使用shift類滑窗函式
roller = s.rolling(window = 2)
roller.sum().shift(-1)

0    3.0
1    5.0
2    NaN
dtype: float64
-----------------
#也可以使用 apply 傳入自定義函式
s.rolling(2).apply(lambda x:list(x)[0]+list(x)[-1]).shift(-1)

0    3.0
1    5.0
2    NaN
dtype: float64

2. 擴張視窗

擴張視窗又稱累計視窗,可以理解為一個動態長度的視窗,其視窗的大小就是從序列開始處到具體操作的對應位置,其使用的聚合函式會作用於這些逐步擴張的視窗上。

s = pd.Series([1, 3, 6, 10])
s.expanding().sum() #累計求和

0     1.0
1     4.0
2    10.0
3    20.0
dtype: float64
類擴張函式屬性
cummax依次給出前1,2,…,n個數的最大值
cumsum依次給出前1,2,…,n個數的和
cumprod依次給出前1,2,…,n個數的積
s = pd.Series([1,3,2,5,4])
s.cummax() #依次給出前1,2,...,n個數的最大值

0    1
1    3
2    3
3    5
4    5
dtype: int64
-----------------
s.cumsum() #依次給出前1,2,...,n個數的和

0     1
1     4
2     6
3    11
4    15
dtype: int64
-----------------
s.cumprod() #依次給出前1,2,...,n個數的積

0      1
1      3
2      6
3     30
4    120
dtype: int64

練一練:
cummax, cumsum, cumprod 函式是典型的類擴張視窗函式,請使用 expanding 物件依次實現它們。

s.expanding().max().astype(np.int64) #s.cummax()
s.expanding().sum().astype(np.int64) #s.cumsum()
s.expanding().apply(lambda x:x.prod()).astype(np.int64) #s.cumprod()

五、練習

Ex1:口袋妖怪資料集

現有一份口袋妖怪的資料集,下面進行一些背景說明:
#代表全國圖鑑編號,不同行存在相同數字則表示為該妖怪的不同狀態
妖怪具有單屬性和雙屬性兩種,對於單屬性的妖怪, Type 2 為缺失值
Total, HP, Attack, Defense, Sp. Atk, Sp. Def, Speed 分別代表種族值、體力、物攻、防禦、特攻、特防、速度,其中種族值為後6項之和

df = pd.read_csv('data/pokemon.csv')
df.head(3)

	#	Name		Type 1	Type 2	Total	HP	Attack	Defense	Sp. Atk	Sp. Def	Speed
0	1	Bulbasaur	Grass	Poison	318		45	49		49		65		65		45
1	2	Ivysaur		Grass	Poison	405		60	62		63		80		80		60
2	3	Venusaur	Grass	Poison	525		80	82		83		100		100		80
  1. 對 HP, Attack, Defense, Sp. Atk, Sp. Def, Speed 進行加總,驗證是否為 Total 值。
#引數axis=1,驗證結果為Total值
df_demo = df[['HP','Attack','Defense','Sp. Atk','Sp. Def','Speed']]
df_demo.sum(axis = 1).head(3)

0    318
1    405
2    525
dtype: int64
-----------------
#根據答案修改:
(df_demo.sum(axis = 1) != df['Total']).mean()
0.0
  1. 對於#重複的妖怪只保留第一條記錄,解決以下問題:
    a. 求第一屬性的種類數量和前三多數量對應的種類
#保留第1條資料,使用drop_duplicates,keep預設
df_dup = df.drop_duplicates(['#'])
#求第一屬性的種類數量,使用nunique()
df_dup['Type 1'].nunique()
>>> 18
#前三多數量對應的種類(每一種類計數(預設從高到低排序),取前三)
df_dup['Type 1'].value_counts().head(3)

Water     105
Normal     93
Grass      66
Name: Type 1, dtype: int64
-----------------
#根據答案修改:
df_dup['Type 1'].value_counts().index[:3]
>>> Index(['Water', 'Normal', 'Grass'], dtype='object')

b. 求第一屬性和第二屬性的組合種類

#取去重的type1和type2
df_type = df_dup.drop_duplicates(['Type 1','Type 2'])
#取行數
df_type.shape[0]
>>> 143

c. 求尚未出現過的屬性組合

#1.求出所有的組合,使用列表推導式
L_full = [i+' '+j for i in df['Type 1'].unique() for j in df['Type 2'].unique()]
>>> TypeError: can only concatenate str (not "float") to str
-----------------
df['Type 1'].unique()
>>> array(['Grass', 'Fire', 'Water', 'Bug', 'Normal', 'Poison', 'Electric',
       'Ground', 'Fairy', 'Fighting', 'Psychic', 'Rock', 'Ghost', 'Ice',
       'Dragon', 'Dark', 'Steel', 'Flying'], dtype=object)
#把numpy陣列轉化為列表:tolist(參考答案)
L_full = [i+' '+j for i in df['Type 1'].unique() for j in (df['Type 1'].unique().tolist() + [' '])]
#2. 列出表中組合,注意type2中缺失值(參考答案)
L_now = [i+' '+j for i, j in zip(df['Type 1'], df['Type 2'].replace(np.nan, ' '))]
#3. 對比取差異(參考答案)
res = set(L_full).difference(set(L_now))
res

{'Bug Bug',
 'Bug Dark',
 'Bug Dragon',
 ...
 'Water Normal',
 'Water Water'}
  1. 按照下述要求,構造 Series :
    a. 取出物攻,超過120的替換為 high ,不足50的替換為 low ,否則設為 mid
Attack = df['Attack']
Attack.clip(50, 120).replace({50:'low',120:'high'}).mask((Attack>=50)&(Attack<=120), 'mid')

0       low
1       mid
2       mid
3       mid
4       mid
       ... 
795     mid
796    high
797     mid
798    high
799     mid
Name: Attack, Length: 800, dtype: object
#參考答案給了另外一種方法
df['Attack'].mask(df['Attack']>120, 'high').mask(df['Attack']<50, 'low').mask((50<=df['Attack'])&(df['Attack']<=120), 'mid')

b. 取出第一屬性,分別用 replace 和 apply 替換所有字母為大寫

#使用replace
df['Type 1'].replace({i:str.upper(i) for i in df['Type 1'].unique()})

0        GRASS
1        GRASS
2        GRASS
3        GRASS
4         FIRE
        ...   
795       ROCK
796       ROCK
797    PSYCHIC
798    PSYCHIC
799       FIRE
Name: Type 1, Length: 800, dtype: object
#使用apply
df['Type 1'].apply(lambda x:str.upper(x))

0        GRASS
1        GRASS
2        GRASS
3        GRASS
4         FIRE
        ...   
795       ROCK
796       ROCK
797    PSYCHIC
798    PSYCHIC
799       FIRE
Name: Type 1, Length: 800, dtype: object

c. 求每個妖怪六項能力的離差,即所有能力中偏離中位數最大的值,新增到 df 並從大到小排序

#離差的概念:max(abs(x-median))
df_ability = df[['HP','Attack','Defense','Sp. Atk','Sp. Def','Speed']]
df['Deviation'] = df_ability.apply(lambda x:np.max((x-x.median()).abs()), axis=1) #求離差
#新增到 df 並倒序:sort_value
df.sort_values('Deviation', ascending=False)

	#	Name	Type 1	Type 2	Total	HP	Attack	Defense	Sp. Atk	Sp. Def	Speed	Deviation
230	213	Shuckle	Bug		Rock	505		20	10		230		10		230		5		215.0
121	113	Chansey	Normal	NaN		450		250	5		5		35		105		50		207.5
261	242	Blissey	Normal	NaN		540		255	10		10		75		135		55		190.0
...

Ex2:指數加權視窗

  1. 作為擴張視窗的 ewm 視窗
    在擴張視窗中,使用者可以使用各類函式進行歷史的累計指標統計,但這些內建的統計函式往往把視窗中的所有元素賦予了同樣的權重。事實上,可以給出不同的權重來賦給視窗中的元素,指數加權視窗就是這樣一種特殊的擴張視窗。
    其中,最重要的引數是 alpha,它決定了預設情況下的視窗權重為 w i = ( 1 − α ) i , i ∈ { 0 , 1 , . . . , t } w_i = (1 - \alpha)^i, i\in \{0, 1, ..., t\} wi=(1α)i,i{0,1,...,t},其中 i=t 表示當前元素, i=0 表示序列的第一個元素。
    從權重公式可以看出,離開當前值越遠則權重越小,若記原序列為 x,更新後的當前元素為 y t y_t yt,此時通過加權公式歸一化後可知:
    在這裡插入圖片描述
    對於 Series 而言,可以用 ewm 物件如下計算指數平滑後的序列:
np.random.seed(0)
s = pd.Series(np.random.randint(-1,2,30).cumsum())
s.head()

0   -1
1   -1
2   -2
3   -2
4   -2
dtype: int32
s.ewm(alpha=0.2).mean().head()

0   -1.000000
1   -1.000000
2   -1.409836
3   -1.609756
4   -1.725845
dtype: float64

請用 expanding 視窗實現。

#自定義函式(參考答案)
def ewm_func(x, alpha=0.2):
    win = (1-alpha)**np.arange(x.shape[0])[::-1]
    res = (win*x).sum()/win.sum()
    return res
s.expanding().apply(ewm_func)

0    -1.000000
1    -1.000000
2    -1.409836
3    -1.609756
...
29   -4.314107
dtype: float64
  1. 作為滑動視窗的 ewm 視窗
    從第1問中可以看到, ewm 作為一種擴張視窗的特例,只能從序列的第一個元素開始加權。現在希望給定一個限制視窗 n ,只對包含自身的最近的 n 個元素作為視窗進行滑動加權平滑。請根據滑窗函式,給出新的 w i w_i wi y t y_t yt 的更新公式,並通過 rolling 視窗實現這一功能。
s.rolling(window=4).apply(ewm_func)

0          NaN
1          NaN
2          NaN
3    -1.609756
4    -1.826558
...
29   -4.783198
dtype: float64

參考文獻

  1. https://blog.csdn.net/brucewong0516/article/details/79096633?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522160828465316780274033842%252522%25252C%252522scm%252522%25253A%25252220140713.130102334…%252522%25257D&request_id=160828465316780274033842&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_click~default-1-79096633.first_rank_v2_pc_rank_v29&utm_term=read_excel
  2. https://blog.csdn.net/sinat_35562946/article/details/81058221?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522160828485016780310131225%252522%25252C%252522scm%252522%25253A%25252220140713.130102334…%252522%25257D&request_id=160828485016780310131225&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_click~default-1-81058221.first_rank_v2_pc_rank_v29&utm_term=read_csv%20%E5%8F%82%E6%95%B0
  3. https://blog.csdn.net/lwgkzl/article/details/80988126
  4. https://blog.csdn.net/dontla/article/details/103068208