Datawhale程式設計實踐(Pandas) Task02
一、檔案的讀取和寫入
excel | csv | txt | |
---|---|---|---|
檔案讀取 | 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
- 公共引數:
型別 | 引數定義 | |
---|---|---|
header | int, list of int, default 0 | 指定作為列名的行,預設0,即取第一行,資料為列名行以下的資料;若資料不含列名,則設定 header = None; |
index_col | int, list of int, default None | 用作行索引的列編號或者列名,如果給定一個序列則有多個行索引 |
usecols | int, str, list-like, or callable default None | 返回一個數據子集,該列表中的值必須可以對應到檔案中的位置(數字可以對應到指定的列)或者是字元傳為檔案中的列名。 |
names | array-like, default None | 指定列的名字,傳入一個list資料 |
skiprows | list-like | 省略指定行數的資料 |
skipfooter | int, 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 |
擴張視窗 | expanding | Series.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
- 對 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
- 對於
#
重複的妖怪只保留第一條記錄,解決以下問題:
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'}
- 按照下述要求,構造 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:指數加權視窗
- 作為擴張視窗的
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
- 作為滑動視窗的 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
參考文獻
- 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
- 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
- https://blog.csdn.net/lwgkzl/article/details/80988126
- https://blog.csdn.net/dontla/article/details/103068208