天給大家準(zhǔn)備了25個pandas高頻實(shí)用技巧,讓你數(shù)據(jù)處理速度直接起飛。文章較長,建議收藏!
首先我們需要先提前下載好示例數(shù)據(jù)集:
import pandas as pd
import numpy as np
drinks=pd.read_csv('http://bit.ly/drinksbycountry')
movies=pd.read_csv('http://bit.ly/imdbratings')
orders=pd.read_csv('http://bit.ly/chiporders', sep='\t')
orders['item_price']=orders.item_price.str.replace('$', '').astype('float')
stocks=pd.read_csv('http://bit.ly/smallstocks', parse_dates=['Date'])
titanic=pd.read_csv('http://bit.ly/kaggletrain')
ufo=pd.read_csv('http://bit.ly/uforeports', parse_dates=['Time'])
有時你需要知道正在使用的pandas版本,特別是在閱讀pandas文檔時。你可以通過輸入以下命令來顯示pandas版本:
pd.__version__
'0.25.8'
如果你還想知道pandas所依賴的模塊的版本,你可以使用show_versions()函數(shù):
pd.show_versions()
INSTALLED VERSIONS
------------------
commit: None
python: 3.7.3.final.0
python-bits: 64
OS: Darwin
OS-release: 18.6.0
machine: x86_64
processor: i386
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
LOCALE: en_US.UTF-8
pandas: 0.24.2
pytest: None
pip: 19.1.1
setuptools: 41.0.1
Cython: None
numpy: 1.16.4
scipy: None
pyarrow: None
xarray: None
IPython: 7.5.0
sphinx: None
patsy: None
dateutil: 2.8.0
pytz: 2019.1
blosc: None
bottleneck: None
tables: None
numexpr: None
feather: None
matplotlib: 3.1.0
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: None
lxml.etree: None
bs4: None
html5lib: None
sqlalchemy: None
pymysql: None
psycopg2: None
jinja2: 2.10.1
s3fs: None
fastparquet: None
pandas_gbq: None
pandas_datareader: None
gcsfs: None
你可以查看到Python,pandas, Numpy, matplotlib等的版本信息。
假設(shè)你需要創(chuàng)建一個示例DataFrame。有很多種實(shí)現(xiàn)的途徑,我最喜歡的方式是傳一個字典給DataFrame constructor,其中字典中的keys為列名,values為列的取值。
df=pd.DataFrame({'col one':[100, 200], 'col two':[300, 400]})
df
如果你需要更大的DataFrame,上述方法將需要太多的輸入。在這種情況下,你可以使用NumPy的 random.rand()函數(shù),定義好該函數(shù)的行數(shù)和列數(shù),并將其傳遞給DataFrame構(gòu)造器:
pd.DataFrame(np.random.rand(4, 8))
這種方式很好,但如果你還想把列名變?yōu)榉菙?shù)值型的,你可以強(qiáng)制地將一串字符賦值給columns參數(shù):
pd.DataFrame(np.random.rand(4, 8), columns=list('abcdefgh'))
你可以想到,你傳遞的字符串的長度必須與列數(shù)相同。
我們來看一下剛才我們創(chuàng)建的示例DataFrame:
df
我更喜歡在選取pandas列的時候使用點(diǎn)(.),但是這對那么列名中含有空格的列不會生效。讓我們來修復(fù)這個問題。
更改列名最靈活的方式是使用rename()函數(shù)。你可以傳遞一個字典,其中keys為原列名,values為新列名,還可以指定axis:
df=df.rename({'col one':'col_one',
'col two':'col_two'},
axis='columns')
使用這個函數(shù)最好的方式是你需要更改任意數(shù)量的列名,不管是一列或者全部的列。
如果你需要一次性重新命令所有的列名,更簡單的方式就是重寫DataFrame的columns屬性:
df.columns=['col_one', 'col_two']
如果你需要做的僅僅是將空格換成下劃線,那么更好的辦法是用str.replace()方法,這是因?yàn)槟愣疾恍枰斎胨械牧忻?/span>
df.columns=df.columns.str.replace(' ', '_')
上述三個函數(shù)的結(jié)果都一樣,可以更改列名使得列名中不含有空格:
df
最后,如果你需要在列名中添加前綴或者后綴,你可以使用add_prefix()函數(shù):
df.add_prefix('X_')
或者使用add_suffix()函數(shù):
df.add_suffix('_Y')
我們來看一下drinks這個DataFame:
drinks.head()
該數(shù)據(jù)集描述了每個國家的平均酒消費(fèi)量。如果你想要將行序反轉(zhuǎn)呢?
最直接的辦法是使用loc函數(shù)并傳遞::-1,跟Python中列表反轉(zhuǎn)時使用的切片符號一致:
drinks.loc[::-1].head()
如果你還想重置索引使得它從0開始呢?
你可以使用reset_index()函數(shù),告訴他去掉完全拋棄之前的索引:
drinks.loc[::-1].reset_index(drop=True).head()
你可以看到,行序已經(jīng)反轉(zhuǎn),索引也被重置為默認(rèn)的整數(shù)序號。
跟之前的技巧一樣,你也可以使用loc函數(shù)將列從左至右反轉(zhuǎn)
drinks.loc[:, ::-1].head()
逗號之前的冒號表示選擇所有行,逗號之后的::-1表示反轉(zhuǎn)所有的列,這就是為什么country這一列現(xiàn)在在最右邊。
這里有drinks這個DataFrame的數(shù)據(jù)類型:
drinks.dtypes
country object
beer_servings int64
spirit_servings int64
wine_servings int64
total_litres_of_pure_alcohol float64
continent object
dtype: object
假設(shè)你僅僅需要選取數(shù)值型的列,那么你可以使用select_dtypes()函數(shù):
drinks.select_dtypes(include='number').head()
這包含了int和float型的列。
你也可以使用這個函數(shù)來選取數(shù)據(jù)類型為object的列:
drinks.select_dtypes(include='object').head()
你還可以選取多種數(shù)據(jù)類型,只需要傳遞一個列表即可:
drinks.select_dtypes(include=['number', 'object', 'category', 'datetime']).head()
你還可以用來排除特定的數(shù)據(jù)類型:
drinks.select_dtypes(exclude='number').head()
我們來創(chuàng)建另一個示例DataFrame:
df=pd.DataFrame({'col_one':['1.1', '2.2', '3.3'],
'col_two':['4.4', '5.5', '6.6'],
'col_three':['7.7', '8.8', '-']})
df
這些數(shù)字實(shí)際上儲存為字符型,導(dǎo)致其數(shù)據(jù)類型為object:
df.dtypes
col_one object
col_two object
col_three object
dtype: object
為了對這些列進(jìn)行數(shù)學(xué)運(yùn)算,我們需要將數(shù)據(jù)類型轉(zhuǎn)換成數(shù)值型。你可以對前兩列使用astype()函數(shù):
df.astype({'col_one':'float', 'col_two':'float'}).dtypes
col_one float64
col_two float64
col_three object
dtype: object
但是,如果你對第三列也使用這個函數(shù),將會引起錯誤,這是因?yàn)檫@一列包含了破折號(用來表示0)但是pandas并不知道如何處理它。
你可以對第三列使用to_numeric()函數(shù),告訴其將任何無效數(shù)據(jù)轉(zhuǎn)換為NaN:
pd.to_numeric(df.col_three, errors='coerce')
0 7.7
1 8.8
2 NaN
Name: col_three, dtype: float64
如果你知道NaN值代表0,那么你可以fillna()函數(shù)將他們替換成0:
pd.to_numeric(df.col_three, errors='coerce').fillna(0)
0 7.7
1 8.8
2 0.0
Name: col_three, dtype: float64
最后,你可以通過apply()函數(shù)一次性對整個DataFrame使用這個函數(shù):
df=df.apply(pd.to_numeric, errors='coerce').fillna(0)
df
僅需一行代碼就完成了我們的目標(biāo),因?yàn)楝F(xiàn)在所有的數(shù)據(jù)類型都轉(zhuǎn)換成float:
df.dtypes
col_one float64
col_two float64
col_three float64
dtype: object
pandas DataFrame被設(shè)計成可以適應(yīng)內(nèi)存,所以有些時候你可以減小DataFrame的空間大小,讓它在你的系統(tǒng)上更好地運(yùn)行起來。
這是drinks這個DataFrame所占用的空間大小:
drinks.info(memory_usage='deep')
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 193 entries, 0 to 192
Data columns (total 6 columns):
country 193 non-null object
beer_servings 193 non-null int64
spirit_servings 193 non-null int64
wine_servings 193 non-null int64
total_litres_of_pure_alcohol 193 non-null float64
continent 193 non-null object
dtypes: float64(1), int64(3), object(2)
memory usage: 30.4 KB
可以看到它使用了304.KB。
如果你對你的DataFrame有操作方面的問題,或者你不能將它讀進(jìn)內(nèi)存,那么在讀取文件的過程中有兩個步驟可以使用來減小DataFrame的空間大小。
第一個步驟是只讀取那些你實(shí)際上需要用到的列,可以調(diào)用usecols參數(shù):
cols=['beer_servings', 'continent']
small_drinks=pd.read_csv('http://bit.ly/drinksbycountry', usecols=cols)
small_drinks.info(memory_usage='deep')
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 193 entries, 0 to 192
Data columns (total 2 columns):
beer_servings 193 non-null int64
continent 193 non-null object
dtypes: int64(1), object(1)
memory usage: 13.6 KB
通過僅讀取用到的兩列,我們將DataFrame的空間大小縮小至13.6KB。
第二步是將所有實(shí)際上為類別變量的object列轉(zhuǎn)換成類別變量,可以調(diào)用dtypes參數(shù):
dtypes={'continent':'category'}
smaller_drinks=pd.read_csv('http://bit.ly/drinksbycountry', usecols=cols, dtype=dtypes)
smaller_drinks.info(memory_usage='deep')
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 193 entries, 0 to 192
Data columns (total 2 columns):
beer_servings 193 non-null int64
continent 193 non-null category
dtypes: category(1), int64(1)
memory usage: 2.3 KB
通過將continent列讀取為category數(shù)據(jù)類型,我們進(jìn)一步地把DataFrame的空間大小縮小至2.3KB。
值得注意的是,如果跟行數(shù)相比,category數(shù)據(jù)類型的列數(shù)相對較小,那么catefory數(shù)據(jù)類型可以減小內(nèi)存占用。
假設(shè)你的數(shù)據(jù)集分化為多個文件,但是你需要將這些數(shù)據(jù)集讀到一個DataFrame中。
舉例來說,我有一些關(guān)于股票的小數(shù)聚集,每個數(shù)據(jù)集為單天的CSV文件。
pd.read_csv('data/stocks1.csv')
pd.read_csv('data/stocks2.csv')
pd.read_csv('data/stocks3.csv')
你可以將每個CSV文件讀取成DataFrame,將它們結(jié)合起來,然后再刪除原來的DataFrame,但是這樣會多占用內(nèi)存且需要許多代碼。
更好的方式為使用內(nèi)置的glob模塊。你可以給glob()函數(shù)傳遞某種模式,包括未知字符,這樣它會返回符合該某事的文件列表。在這種方式下,glob會查找所有以stocks開頭的CSV文件:
from glob import glob
stock_files=sorted(glob('data/stocks*.csv'))
stock_files
['data/stocks1.csv', 'data/stocks2.csv', 'data/stocks3.csv']
glob會返回任意排序的文件名,這就是我們?yōu)槭裁匆肞ython內(nèi)置的sorted()函數(shù)來對列表進(jìn)行排序。
我們以生成器表達(dá)式用read_csv()函數(shù)來讀取每個文件,并將結(jié)果傳遞給concat()函數(shù),這會將單個的DataFrame按行來組合:
pd.concat((pd.read_csv(file) for file in stock_files))
不幸的是,索引值存在重復(fù)。為了避免這種情況,我們需要告訴concat()函數(shù)來忽略索引,使用默認(rèn)的整數(shù)索引:
pd.concat((pd.read_csv(file) for file in stock_files), ignore_index=True)
上一個技巧對于數(shù)據(jù)集中每個文件包含行記錄很有用。但是如果數(shù)據(jù)集中的每個文件包含的列信息呢?
這里有一個例子,dinks數(shù)據(jù)集被劃分成兩個CSV文件,每個文件包含三列:
pd.read_csv('data/drinks1.csv').head()
pd.read_csv('data/drinks2.csv').head()
同上一個技巧一樣,我們以使用glob()函數(shù)開始。這一次,我們需要告訴concat()函數(shù)按列來組合:
drink_files=sorted(glob('data/drinks*.csv'))
pd.concat((pd.read_csv(file) for file in drink_files), axis='columns').head()
現(xiàn)在我們的DataFrame已經(jīng)有六列了。
假設(shè)你將一些數(shù)據(jù)儲存在Excel或者Google Sheet中,你又想要盡快地將他們讀取至DataFrame中。
你需要選擇這些數(shù)據(jù)并復(fù)制至剪貼板。然后,你可以使用read_clipboard()函數(shù)將他們讀取至DataFrame中:
df=pd.read_clipboard()
df
和read_csv()類似,read_clipboard()會自動檢測每一列的正確的數(shù)據(jù)類型:
df.dtypes
Column A int64
Column B float64
Column C object
dtype: object
我們再復(fù)制另外一個數(shù)據(jù)至剪貼板:
df=pd.read_clipboard()
df
神奇的是,pandas已經(jīng)將第一列作為索引了:
df.index
Index(['Alice', 'Bob', 'Charlie'], dtype='object')
需要注意的是,如果你想要你的工作在未來可復(fù)制,那么read_clipboard()并不值得推薦。
假設(shè)你想要將一個DataFrame劃分為兩部分,隨機(jī)地將75%的行給一個DataFrame,剩下的25%的行給另一個DataFrame。
舉例來說,我們的movie ratings這個DataFrame有979行:
len(movies)
979
假設(shè)你想要將一個DataFrame劃分為兩部分,隨機(jī)地將75%的行給一個DataFrame,剩下的25%的行給另一個DataFrame。
舉例來說,我們的movie ratings這個DataFrame有979行:
movies_1=movies.sample(frac=0.75, random_state=1234)
接著我們使用drop()函數(shù)來舍棄“moive_1”中出現(xiàn)過的行,將剩下的行賦值給"movies_2"DataFrame:
movies_2=movies.drop(movies_1.index)
你可以發(fā)現(xiàn)總的行數(shù)是正確的:
len(movies_1) + len(movies_2)
979
你還可以檢查每部電影的索引,或者"moives_1":
movies_1.index.sort_values()
Int64Index([ 0, 2, 5, 6, 7, 8, 9, 11, 13, 16,
...
966, 967, 969, 971, 972, 974, 975, 976, 977, 978],
dtype='int64', length=734)
或者"moives_2":
movies_2.index.sort_values()
Int64Index([ 1, 3, 4, 10, 12, 14, 15, 18, 26, 30,
...
931, 934, 937, 941, 950, 954, 960, 968, 970, 973],
dtype='int64', length=245)
需要注意的是,這個方法在索引值不唯一的情況下不起作用。
讀者注:該方法在機(jī)器學(xué)習(xí)或者深度學(xué)習(xí)中很有用,因?yàn)樵谀P陀?xùn)練前,我們往往需要將全部數(shù)據(jù)集按某個比例劃分成訓(xùn)練集和測試集。該方法既簡單又高效,值得學(xué)習(xí)和嘗試。
我們先看一眼movies這個DataFrame:
movies.head()
其中有一列是genre(類型):
movies.genre.unique()
array(['Crime', 'Action', 'Drama', 'Western', 'Adventure', 'Biography',
'Comedy', 'Animation', 'Mystery', 'Horror', 'Film-Noir', 'Sci-Fi',
'History', 'Thriller', 'Family', 'Fantasy'], dtype=object)
比如我們想要對該DataFrame進(jìn)行過濾,我們只想顯示genre為Action或者Drama或者Western的電影,我們可以使用多個條件,以"or"符號分隔
movies[(movies.genre=='Action') |
(movies.genre=='Drama') |
(movies.genre=='Western')].head()
但是,你實(shí)際上可以使用isin()函數(shù)將代碼寫得更加清晰,將genres列表傳遞給該函數(shù):
movies[movies.genre.isin(['Action', 'Drama', 'Western'])].head()
如果你想要進(jìn)行相反的過濾,也就是你將吧剛才的三種類型的電影排除掉,那么你可以在過濾條件前加上破浪號:
movies[~movies.genre.isin(['Action', 'Drama', 'Western'])].head()
這種方法能夠起作用是因?yàn)樵赑ython中,波浪號表示“not”操作。
假設(shè)你想要對movies這個DataFrame通過genre進(jìn)行過濾,但是只需要前3個數(shù)量最多的genre。
我們對genre使用value_counts()函數(shù),并將它保存成counts(type為Series):
counts=movies.genre.value_counts()
counts
Drama 278
Comedy 156
Action 136
Crime 124
Biography 77
Adventure 75
Animation 62
Horror 29
Mystery 16
Western 9
Sci-Fi 5
Thriller 5
Film-Noir 3
Family 2
Fantasy 1
History 1
Name: genre, dtype: int64
該Series的nlargest()函數(shù)能夠輕松地計算出Series中前3個最大值:
counts.nlargest(3)
Drama 278
Comedy 156
Action 136
Name: genre, dtype: int64
事實(shí)上我們在該Series中需要的是索引:
counts.nlargest(3).index
Index(['Drama', 'Comedy', 'Action'], dtype='object')
最后,我們將該索引傳遞給isin()函數(shù),該函數(shù)會把它當(dāng)成genre列表:
movies[movies.genre.isin(counts.nlargest(3).index)].head()
樣,在DataFrame中只剩下Drame, Comdey, Action這三種類型的電影了。
我們來看一看UFO sightings這個DataFrame:
ufo.head()
你將會注意到有些值是缺失的。??為了找出每一列中有多少值是缺失的,你可以使用isna()函數(shù),然后再使用sum():
ufo.isna().sum()
City 25
Colors Reported 15359
Shape Reported 2644
State 0
Time 0
dtype: int64
isna()會產(chǎn)生一個由True和False組成的DataFrame,sum()會將所有的True值轉(zhuǎn)換為1,F(xiàn)alse轉(zhuǎn)換為0并把它們加起來。
類似地,你可以通過mean()和isna()函數(shù)找出每一列中缺失值的百分比。
ufo.isna().mean()
City 0.001371
Colors Reported 0.842004
Shape Reported 0.144948
State 0.000000
Time 0.000000
dtype: float64
如果你想要舍棄那些包含了缺失值的列,你可以使用dropna()函數(shù):
ufo.dropna(axis='columns').head()
或者你想要舍棄那么缺失值占比超過10%的列,你可以給dropna()設(shè)置一個閾值:
ufo.dropna(thresh=len(ufo)*0.9, axis='columns').head()
len(ufo)返回總行數(shù),我們將它乘以0.9,以告訴pandas保留那些至少90%的值不是缺失值的列。
我們先創(chuàng)建另一個新的示例DataFrame:
df=pd.DataFrame({'name':['John Arthur Doe', 'Jane Ann Smith'],
'location':['Los Angeles, CA', 'Washington, DC']})
df
如果我們需要將“name”這一列劃分為三個獨(dú)立的列,用來表示first, middle, last name呢?我們將會使用str.split()函數(shù),告訴它以空格進(jìn)行分隔,并將結(jié)果擴(kuò)展成一個DataFrame:
df.name.str.split(' ', expand=True)
這三列實(shí)際上可以通過一行代碼保存至原來的DataFrame:
df[['first', 'middle', 'last']]=df.name.str.split(' ', expand=True)
df
如果我們想要劃分一個字符串,但是僅保留其中一個結(jié)果列呢?比如說,讓我們以", "來劃分location這一列:
df.location.str.split(', ', expand=True)
如果我們只想保留第0列作為city name,我們僅需要選擇那一列并保存至DataFrame:
df['city']=df.location.str.split(', ', expand=True)[0]
df
我們創(chuàng)建一個新的示例DataFrame:
df=pd.DataFrame({'col_one':['a', 'b', 'c'], 'col_two':[[10, 40], [20, 50], [30, 60]]})
df
這里有兩列,第二列包含了Python中的由整數(shù)元素組成的列表。
如果我們想要將第二列擴(kuò)展成DataFrame,我們可以對那一列使用apply()函數(shù)并傳遞給Series constructor:
df_new=df.col_two.apply(pd.Series)
df_new
通過使用concat()函數(shù),我們可以將原來的DataFrame和新的DataFrame組合起來:
pd.concat([df, df_new], axis='columns')
我們來看一眼從Chipotle restaurant chain得到的orders這個DataFrame:
orders.head(10)
每個訂單(order)都有訂單號(order_id),包含一行或者多行。為了找出每個訂單的總價格,你可以將那個訂單號的價格(item_price)加起來。比如,這里是訂單號為1的總價格:
orders[orders.order_id==1].item_price.sum()
11.56
如果你想要計算每個訂單的總價格,你可以對order_id使用groupby(),再對每個group的item_price進(jìn)行求和。
orders.groupby('order_id').item_price.sum().head()
order_id
1 11.56
2 16.98
3 12.67
4 21.00
5 13.70
Name: item_price, dtype: float64
但是,事實(shí)上你不可能在聚合時僅使用一個函數(shù),比如sum()。為了對多個函數(shù)進(jìn)行聚合,你可以使用agg()函數(shù),傳給它一個函數(shù)列表,比如sum()和count():
orders.groupby('order_id').item_price.agg(['sum', 'count']).head()
這將告訴我們沒定訂單的總價格和數(shù)量。
我們再看一眼orders這個DataFrame:
orders.head(10)
如果我們想要增加新的一列,用于展示每個訂單的總價格呢?回憶一下,我們通過使用sum()函數(shù)得到了總價格:
orders.groupby('order_id').item_price.sum().head()
order_id
1 11.56
2 16.98
3 12.67
4 21.00
5 13.70
Name: item_price, dtype: float64
sum()是一個聚合函數(shù),這表明它返回輸入數(shù)據(jù)的精簡版本(reduced version )。
換句話說,sum()函數(shù)的輸出:
len(orders.groupby('order_id').item_price.sum())
1834
比這個函數(shù)的輸入要小:
len(orders.item_price)
4622
解決的辦法是使用transform()函數(shù),它會執(zhí)行相同的操作但是返回與輸入數(shù)據(jù)相同的形狀:
total_price=orders.groupby('order_id').item_price.transform('sum')
len(total_price)
4622
我們將這個結(jié)果存儲至DataFrame中新的一列:
orders['total_price']=total_price
orders.head(10)
你可以看到,每個訂單的總價格在每一行中顯示出來了。
這樣我們就能方便地甲酸每個訂單的價格占該訂單的總價格的百分比:
orders['percent_of_total']=orders.item_price / orders.total_price
orders.head(10)
我們看一眼另一個數(shù)據(jù)集:
titanic.head()
這就是著名的Titanic數(shù)據(jù)集,它保存了Titanic上乘客的信息以及他們是否存活。
如果你想要對這個數(shù)據(jù)集做一個數(shù)值方面的總結(jié),你可以使用describe()函數(shù):
titanic.describe()
但是,這個DataFrame結(jié)果可能比你想要的信息顯示得更多。
如果你想對這個結(jié)果進(jìn)行過濾,只想顯示“五數(shù)概括法”(five-number summary)的信息,你可以使用loc函數(shù)并傳遞"min"到"max"的切片:
titanic.describe().loc['min':'max']
如果你不是對所有列都感興趣,你也可以傳遞列名的切片:
titanic.describe().loc['min':'max', 'Pclass':'Parch']
Titanic數(shù)據(jù)集的Survived列由1和0組成,因此你可以對這一列計算總的存活率:
titanic.Survived.mean()
0.3838383838383838
如果你想對某個類別,比如“Sex”,計算存活率,你可以使用groupby():
titanic.groupby('Sex').Survived.mean()
Sex
female 0.742038
male 0.188908
Name: Survived, dtype: float64
如果你想一次性對兩個類別變量計算存活率,你可以對這些類別變量使用groupby():
titanic.groupby(['Sex', 'Pclass']).Survived.mean()
Sex Pclass
female 1 0.968085
2 0.921053
3 0.500000
male 1 0.368852
2 0.157407
3 0.135447
Name: Survived, dtype: float64
該結(jié)果展示了由Sex和Passenger Class聯(lián)合起來的存活率。它存儲為一個MultiIndexed Series,也就是說它對實(shí)際數(shù)據(jù)有多個索引層級。
這使得該數(shù)據(jù)難以讀取和交互,因此更為方便的是通過unstack()函數(shù)將MultiIndexed Series重塑成一個DataFrame:
titanic.groupby(['Sex', 'Pclass']).Survived.mean().unstack()
該DataFrame包含了與MultiIndexed Series一樣的數(shù)據(jù),不同的是,現(xiàn)在你可以用熟悉的DataFrame的函數(shù)對它進(jìn)行操作。
如果你經(jīng)常使用上述的方法創(chuàng)建DataFrames,你也許會發(fā)現(xiàn)用pivot_table()函數(shù)更為便捷:
titanic.pivot_table(index='Sex', columns='Pclass', values='Survived', aggfunc='mean')
想要使用數(shù)據(jù)透視表,你需要指定索引(index), 列名(columns), 值(values)和聚合函數(shù)(aggregation function)。
數(shù)據(jù)透視表的另一個好處是,你可以通過設(shè)置margins=True輕松地將行和列都加起來:
titanic.pivot_table(index='Sex', columns='Pclass', values='Survived', aggfunc='mean',
margins=True)
T這個結(jié)果既顯示了總的存活率,也顯示了Sex和Passenger Class的存活率。
最后,你可以創(chuàng)建交叉表(cross-tabulation),只需要將聚合函數(shù)由"mean"改為"count":
titanic.pivot_table(index='Sex', columns='Pclass', values='Survived', aggfunc='count',
margins=True)
這個結(jié)果展示了每一對類別變量組合后的記錄總數(shù)。
我們來看一下Titanic數(shù)據(jù)集中的Age那一列:
titanic.Age.head(10)
0 22.0
1 38.0
2 26.0
3 35.0
4 35.0
5 NaN
6 54.0
7 2.0
8 27.0
9 14.0
Name: Age, dtype: float64
它現(xiàn)在是連續(xù)性數(shù)據(jù),但是如果我們想要將它轉(zhuǎn)變成類別數(shù)據(jù)呢?
一個解決辦法是對年齡范圍打標(biāo)簽,比如"adult", "young adult", "child"。實(shí)現(xiàn)該功能的最好方式是使用cut()函數(shù):
pd.cut(titanic.Age, bins=[0, 18, 25, 99], labels=['child', 'young adult', 'adult']).head(10)
0 young adult
1 adult
2 adult
3 adult
4 adult
5 NaN
6 adult
7 child
8 adult
9 child
Name: Age, dtype: category
Categories (3, object): [child < young adult < adult]
這會對每個值打上標(biāo)簽。0到18歲的打上標(biāo)簽"child",18-25歲的打上標(biāo)簽"young adult",25到99歲的打上標(biāo)簽“adult”。
注意到,該數(shù)據(jù)類型為類別變量,該類別變量自動排好序了(有序的類別變量)。
我們再來看一眼Titanic 數(shù)據(jù)集:
titanic.head()
注意到,Age列保留到小數(shù)點(diǎn)后1位,F(xiàn)are列保留到小數(shù)點(diǎn)后4位。如果你想要標(biāo)準(zhǔn)化,將顯示結(jié)果保留到小數(shù)點(diǎn)后2位呢?
你可以使用set_option()函數(shù):
pd.set_option('display.float_format', '{:.2f}'.format)
titanic.head()
set_option()函數(shù)中第一個參數(shù)為選項(xiàng)的名稱,第二個參數(shù)為Python格式化字符。可以看到,Age列和Fare列現(xiàn)在已經(jīng)保留小數(shù)點(diǎn)后兩位。注意,這并沒有修改基礎(chǔ)的數(shù)據(jù)類型,而只是修改了數(shù)據(jù)的顯示結(jié)果。
你也可以重置任何一個選項(xiàng)為其默認(rèn)值:
pd.reset_option('display.float_format')
對于其它的選項(xiàng)也是類似的使用方法。
上一個技巧在你想要修改整個jupyter notebook中的顯示會很有用。但是,一個更靈活和有用的方法是定義特定DataFrame中的格式化(style)。
我們回到stocks這個DataFrame:
stocks
我們可以創(chuàng)建一個格式化字符串的字典,用于對每一列進(jìn)行格式化。然后將其傳遞給DataFrame的style.format()函數(shù):
format_dict={'Date':'{:%m/%d/%y}', 'Close':'${:.2f}', 'Volume':'{:,}'}
stocks.style.format(format_dict)
注意到,Date列是month-day-year的格式,Close列包含一個$符號,Volume列包含逗號。
我們可以通過鏈?zhǔn)秸{(diào)用函數(shù)來應(yīng)用更多的格式化:
(stocks.style.format(format_dict)
.hide_index()
.highlight_min('Close', color='red')
.highlight_max('Close', color='lightgreen')
)
我們現(xiàn)在隱藏了索引,將Close列中的最小值高亮成紅色,將Close列中的最大值高亮成淺綠色。
這里有另一個DataFrame格式化的例子:
(stocks.style.format(format_dict)
.hide_index()
.background_gradient(subset='Volume', cmap='Blues')
)
Volume列現(xiàn)在有一個漸變的背景色,你可以輕松地識別出大的和小的數(shù)值。
最后一個例子:
(stocks.style.format(format_dict)
.hide_index()
.bar('Volume', color='lightblue', align='zero')
.set_caption('Stock Prices from October 2016')
)
現(xiàn)在,Volumn列上有一個條形圖,DataFrame上有一個標(biāo)題。請注意,還有許多其他的選項(xiàng)你可以用來格式化DataFrame。
假設(shè)你拿到一個新的數(shù)據(jù)集,你不想要花費(fèi)太多力氣,只是想快速地探索下。那么你可以使用pandas-profiling這個模塊。在你的系統(tǒng)上安裝好該模塊,然后使用ProfileReport()函數(shù),傳遞的參數(shù)為任何一個DataFrame。它會返回一個互動的HTML報告:
使用示例如下(只顯示第一部分的報告):
import pandas_profiling
pandas_profiling.ProfileReport(titanic)
本文轉(zhuǎn)載自數(shù)據(jù)STUDIO,作者云朵君,三年互聯(lián)網(wǎng)數(shù)據(jù)分析經(jīng)驗(yàn),擅長Excel、SQL、Python、PowerBI數(shù)據(jù)處理工具,數(shù)據(jù)可視化、商業(yè)數(shù)據(jù)分析技能,統(tǒng)計學(xué)、機(jī)器學(xué)習(xí)知識,持續(xù)創(chuàng)作數(shù)據(jù)分析內(nèi)容,點(diǎn)贊關(guān)注,不迷路。
.首先我們新建一個 400*400的文檔,設(shè)置前景色81C1E9、背景色2785DA,線性漸變垂直拉制背景。
2.按F5進(jìn)入筆刷調(diào)板。
畫筆筆尖形狀:筆尖類型 柔角100 ,直徑 100Px,間距 25。
形狀動態(tài):大小抖動 100%,最小直徑 20%,角度抖動 20%。
散布:兩軸 120%,數(shù)量 5 ,數(shù)量抖動 100%。
紋理:圖樣 云彩(128*128 灰度),縮放 100%,模式 顏色加深,深度 100%。
其他動態(tài):不透明度抖動 50%,流量抖動 20%。
==============================
公眾號:春樹鎮(zhèn)
研究討論:互聯(lián)網(wǎng)技術(shù),php開發(fā),網(wǎng)站建議,app開發(fā),html5開發(fā),設(shè)計,小說,電影。
戶:一家云集
行業(yè):建材
產(chǎn)品/解決方案:建材B2B供應(yīng)鏈系統(tǒng)
項(xiàng)目背景
——
建材行業(yè)擁有一個巨大的市場,但建材行業(yè)的平臺運(yùn)營效果不佳,主要問題在于建材行業(yè)除了建材采購之外還需要施工服務(wù),而且從業(yè)人員文化素質(zhì)普遍偏低,行業(yè)品類多。【數(shù)商云】基于以上的商業(yè)痛點(diǎn),通過主流的開發(fā)技術(shù)為企業(yè)打造的是一個行業(yè)撮合交易的平臺,提供深度的建材采購,用工平臺服務(wù),一鍵式完成從采購至用工的門店與生產(chǎn)廠家的供需服務(wù)。
方案亮點(diǎn)
——
建材電子商務(wù)采購管理系統(tǒng)解決方案可以為企業(yè)實(shí)現(xiàn)集團(tuán)物資的全流程管理,從需求計劃、招標(biāo)(競標(biāo)、詢比價)、采購合同、采購到貨、采購結(jié)算、統(tǒng)計分析等方面進(jìn)行全面細(xì)致的物資采購管理與控制。
● 提供入駐建材電商網(wǎng)站資格的功能
供應(yīng)商注冊商家,提交企業(yè)資質(zhì),建材B2B電商平臺對其資質(zhì)進(jìn)行審核,商家開通店鋪,上架商品,采購商在線采購。
● 實(shí)現(xiàn)精細(xì)化運(yùn)營服務(wù)功能
接入自動化營銷系統(tǒng),基于全鏈數(shù)據(jù)分析,幫助建材B2B供應(yīng)鏈平臺拓展上下游營銷渠道,精準(zhǔn)獲取客戶,個性化維系客戶,科學(xué)決策,實(shí)現(xiàn)平臺精細(xì)化運(yùn)營。
● 提供B2B電子合同功能
平臺通過CA的數(shù)字認(rèn)證技術(shù)和數(shù)字證書產(chǎn)品來實(shí)現(xiàn)有效的電子簽名,讓電子合同符合《電子簽名法》,具備防篡改,抗抵賴的特性,從而擁有和紙質(zhì)合同同等的法律效力。
● 多渠道系統(tǒng)與家B2B電子商務(wù)網(wǎng)站對接整合
采用html5技術(shù),移動端與PC端完美的結(jié)合,會員、商品、訂單、積分、預(yù)存款等功能與PC端無B2B商城網(wǎng)站實(shí)現(xiàn)無縫對接。
實(shí)施價值
——
基于電子商務(wù)的建材物資采購平臺使企業(yè)領(lǐng)導(dǎo)層可以方便地了解每一種物資的價格、數(shù)量、庫存情況,合同的執(zhí)行情況,資金的使用情況以及供應(yīng)商情況等各種信息,針對物資采購過程中出現(xiàn)的問題,快速反應(yīng),有效的對領(lǐng)導(dǎo)層決策提供數(shù)據(jù)支撐。
本文由數(shù)商云?云朵匠原創(chuàng),商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請標(biāo)明:數(shù)商云原創(chuàng)
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。