Python科學計算庫常用API入門

最近一直在忙著處理數據,以下是我作為python和數據分析的入門小白,在最近幾周的工作中總結的一些經驗。

一、Pandas

高性能、簡單易用的數據結構和數據分析工具

1 DataFrame/Series常用

DataFrame

構建DataFrame

df = pd.DataFrame(numpy_ndarray, columns=['col1','col2',...] )
df = pd.DataFrame(some_list_of_set, columns=['col1','col2',...] )
df = pd.DataFrame(some_dict_of_series_or_arrays_or_list)

web_stats = {'Day':[1,2,3,4,5,6],
            'Visitors':[43,53,34,45,64,34],
            'Bounce_Rate':[65,72,62,64,54,66]}

df = pd.DataFrame(web_stats)

查看頭部
df.head()
查看尾部(n個元素)
df.tail(n)

以Day字段為索引
df = df.set_index('Day')

選擇某一列 df['Visitors']df.Visitors 如果有空格,使用第一種

將df一列轉為list(列行轉)
df.Visitors.tolist()

多列轉數組
np.array(df[['Bounce_Rate','Visitors']])

重命名列名

df.columns = ['Renamed_col1','Renamed_col2'] 
df = df.rename(columns=={oldColName: newColName})

數據的快速統計匯總
df.describe()

查看更多的百分位數
df.describe(percentiles=[.20,.40,.80,.90,.95])

篩選:

df[df.A > 0] # 字段A大于0的
df.query(' k == "/pay/v4/order/pay/consume" and ct > 4000')
df[(df['class'] == 'Iris-virginica') & (df['petal width'] > 2.2)]

刪除多列:
df.drop(['col1', 'col2'], axis=1) # inplace=True指定替換原df

刪除多記錄:
df.drop([22,33], axis=0)

分組聚合查詢:

aggregations = {
    'ct': { # work on the "duration" column
        'total': 'sum',  # get the sum, and call this result 'total_duration'
        'average': 'mean', # get mean, call result 'average_duration'
        'count': 'count',
        'max': 'max',
        'min': 'min',
        'quantile_0.5': lambda x: x.quantile(0.5),
        'quantile_0.75': lambda x: x.quantile(0.75),
        'quantile_0.95': lambda x: x.quantile(0.95)
    },
}

easy_df.groupby("k").aggregate(aggregations)
# 查詢
slow_pay_df = easy_df[ (easy_df.k == 'pay/consume' ) & ( easy_df.ct > 3000 )] 
# 排序
easy_agg = easy_df.sort_values(by=[('ct','average')], ascending=False) # 多index的要使用tuple傳入列名

選擇Pclass和Survived列,按照Pclass聚合,按平均值降序排列查看:

train_df[['Pclass', 'Survived']].groupby(['Pclass'], as_index=False).mean().sort_values(by='Survived', ascending=False)

分組count:
df1.groupby('p.trade_status')['p.trade_status'].value_counts()

處理缺失數據:
df = df.dropna(axis=1, thresh=100) # 刪除非NaN值小于100的列

map: 轉變數據框(df)中的某個列的列數據

將class列的數據替換為更簡單的名稱,并將原列替換
df['class'] = df['class'].map({'Iris-setosa': 'SET', 'Iris-virginica': 'VIR', 'Iris-versicolor': 'VER'})

apply :
既可以在DataFrame上工作,也可在Series上工作。
df['wide petal'] = df['petal width'].apply(lambda v: 1 if v >= 1.3 else 0)
axis :

  • 0 or ‘index’: apply function to each column
  • 1 or ‘columns’: apply function to each row

按行處理整個df
df['petal area'] = df.apply(lambda r: r['petal length'] * r['petal width'], axis=1)

按行更新,如果是nan就更新成另一個行

def update_appkey(row, data=data):
    if row.app_key_x != row.app_key_x:
        print('update ',row['包名'], ' ',row.app_key_y)
        row.app_key_x = row.app_key_y
    return row
pdata = mdata.apply(update_appkey, axis=1).copy()

在apply的函數中,獲取行號:使用row.name屬性

applymap :對整個df所有數據單元執行一個函數
df.applymap(lambda v: np.log(v) if isinstance(v, float) else v)

數據切片 iloc
df.iloc[:3, :2]

tip: ix vs iloc vs loc

  • loc 通過行標簽索引行數據(works on labels in the index.),如loc[1]表示索引的是第一行,loc['d']表示索引的是'd'行,loc[:, ['c']] 索引'c'列
  • iloc 通過行號獲取行數據(works on the positions in the index (so it only takes integers)) ,
  • ix usually tries to behave like loc but falls back to behaving like iloc if the label is not in the index. pandas 0.20.0 及以上廢除

重置索引(如截取了一個子df,索引保持原樣,可以重置索引從0開始)
df.reset_index(drop=True)

檢查數據相關性:
df.corr()
通過傳遞method參數,還可以切換到Kendall's tau或Spearman's
df.corr(method='spearman')
df.corr(method='kendall')

Series :

unique() 相當與sql distinct
df['class'].unique()

round : 四舍五入
df.round(n) # 保留n位小數

df['col'].round(n)

找重復數據:
df.duplicated()

pivot_table 以電子表格形式顯示數據
names.pivot_table('births',columns='sex',aggfunc=sum,index='year') # 統計對象為births列,縱坐標以sex列劃分,橫坐標為year,使用sum函數聚合

字符串替換:
f['date'] = f['date'].str.replace('日','')

聚合Group by :
使用group by - apply 分組并加入列

def add_prop(group):
    # 注意變為float
    births = group.births.astype(float)
    group['prop'] = births / births.sum()
    return group
names = names.groupby(['year','sex']).apply(add_prop) # 某年內某個性別分組
names

分組取top 1000:
top1000 = names.groupby(['year','sex']).apply(lambda g : g.sort_values(by='births', ascending=False)[:1000])

樣本值的累積和:
df.cumsum()

找到已排序的series中n應該插入的位置:series.searchsorted(n)

s = pd.Series([1,3,5,7,9])
s.searchsorted(2) # 1

處理時間:
login_df['createtime'] = pd.to_datetime(login_df[['year','month','day','hour','minute','second']]) # login_df包含了年月日時分秒的列

2 I/O Basics

從csv文件讀取到df:
df = pd.read_csv('filename')
從df寫入到csv:
df.to_csv('newcsv.csv')

讀取頁面的tables為dataFrame list:
dfs = df.read_html('https://simple.wikipedia.org/wiki/List_of_U.S._states')

處理utf8編碼的嵌套json數據(規則化json數據):

import pandas as pd
import codecs
import json
path = 'some_nested_json_with_utf8_coded.json'

with codecs.open(path, 'r', 'utf-8') as json_data:
    json_dicts = json.load(json_data)
    json_dicts = pd.io.json.json_normalize(json_dicts)  # 處理嵌套json
    df = pd.DataFrame(json_dicts)
# df = pd.read_json(path)  # 這兩種都一樣
df.head()

讀取mysql數據到df(pandas處理sql要借助SQLAlchemy,一個類似java中mybatis的orm工具,具體實現還要依賴各種數據庫連接驅動模塊):

conn = 'mysql+pymysql://user:password@192.168.3.2:3306/dbname?charset=utf8'# pymysql也可更換為包含的庫如mysqlconnector
app_df = pd.read_sql_query(u'select col_name1 from table_name1', con=conn)

讀取oracle大批數據到df:

import cx_Oracle

ip = '172.16.1.63'
port = 1521
SID = 'ucbi' # oracle SID
dsn_tns = cx_Oracle.makedsn(ip, port, SID)

conn = cx_Oracle.connect(user='user',password='password',dsn=dsn_tns)
pool_generator = pd.read_sql('select * from table_name1', con=conn, chunksize=20000) # 每次讀20000條數據

dfs = []
for chunk in pool_generator:
    print('process ',len(dfs))
    dfs.append(chunk)

pool = pd.concat(dfs,ignore_index=True)
pool

df數據寫入到oracle

# 寫入
import cx_Oracle
from sqlalchemy import create_engine

from sqlalchemy import types
# 指定類型,否則對df中object類型默認使用CLOB,速度慢到令人發指 https://stackoverflow.com/questions/42727990/speed-up-to-sql-when-writing-pandas-dataframe-to-oracle-database-using-sqlalch
dtyp = {c:types.VARCHAR(df[c].str.len().max())
        for c in df.columns[df.dtypes == 'object'].tolist()}

ip = '172.16.1.63'
port = 1521
SID = 'ucbi'
dsn_tns = cx_Oracle.makedsn(ip, port, SID)
print(dsn_tns)
engine = create_engine('oracle+cx_oracle://ucenter:passwd@%s' % dsn_tns)

df.to_sql('table_name', engine, chunksize=20000, if_exists='replace',dtype=dtyp ) # 每次重新創建表

3 數據合并:

join: 主要用于索引上的合并
df.join(self, other, on=None, how='left', lsuffix='', rsuffix='',sort=False)

merge: 默認以重疊的列名當做連接鍵,默認inner連接
pd.merge(df1,df2,on='Year',how='outer')
how 類似mysql join方式,有left, right, inner, outer ,連接鍵名稱不同,可使用left_on和right_on指定;以索引當做連接鍵:left_index=true,right_index=True
on可以指定多個col,on=['Year','Month']

concat: 相當于DB中的全連接(union all) concat方法相當于數據庫中的全連接(UNION ALL),可以指定按某個軸進行連接,也可以指定連接的方式join(outer,inner 只有這兩種)。與數據庫不同的時concat不會去重,要達到去重的效果可以使用drop_duplicates方法
pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False)
常用:
pd.concat(some_list, ignore_index=True)

4 持久化

python原生pickle

import pickle
# 序列化
pickle_out = open('picklename','wb')
pickle.dump(df,pickle_out)
pickle_out.close()
# 反序列化
pickle_in = open('picklename'),'rb')
df = pickle.load(pickle_in)

pandas pickle

df.to_pickle('picklename2')
df2 = pd.read_pickle('picklename2')

5 其他

pd.get_dummies 屬性平展

data_train['Cabin'] # 為'Yes'和'No'數據
dummies_Cabin = pd.get_dummies(data_train['Cabin'], prefix= 'Cabin') # 獲取Cabin_Yes 和 Cabin_No兩列,并按0,1展示

pandas中判斷NaN類型:

def isNaN(num):
     return num != num

需要篩選后處理數據時,使用copy,否則一些操作會返回一個view,這樣在更新時就會有問題

多level降低:(尤其適用于在excel讀入的多表頭數據)
frame.columns = frame.columns.droplevel()

bool 數組取反使用"-"
pool[ -(pool.USERID.str.contains('\|'))]

df中index不是column!

二、numpy

np.allclose : 檢查是否近似
np.allclose(names.groupby(['year','sex']).prop.sum(),1)

四舍五入
np.round(3.45, 0)

取隨機整數
np.random.randint(50) # 0~49

np.array配合查找df

mask = np.array(['lesl' in x.lower() for x in all_names])
lesley_like = all_names[mask]

創建ndarray:
arr1 = np.arra([...])
查看數組維度
arr1.ndim
數組形狀:
arr1.shape
數據結構
arr1.dtype
使用zeros或ones創建長度或形狀全0或全1的數組
np.zeros(10)或np.zeros((3,6))
使用empty創建一個沒有任何具體值的數組(并非返回全0數組,很多情況下返回未初始化的垃圾值)
python內置range的數組版本:
np.arange(10)
創建一個正方的N*N單位矩陣(對角線為1,其余為0)
np.eye(n)

dtype是一個特殊的對象,它含有ndarray將一塊內存解釋為特定數據類型所需的信息
np.array([1,2,3], dtype=np.float64)
np.array([1,2,3], dtype=np.int32)

numpy數據類型:
int8, uint8
int16, uint16
int32, uint32
int64, uint64
float16
float32 標準的單精度浮點數。與c的float兼容
float64 標準的雙精度浮點數。與c的double和python的float對象兼容
float128
complex64, complex128, complex256 復數
bool
object Python對象類型
string_ 固定長度的字符串類型(每個字符1個字節)
unicode_ 固定長度的unicode類型(字節數由平臺決定)

使用astype轉換dtype(總會創建一個新數組)
arr.astype(np.float64)

不同大小的數組之間的運算叫做廣播。

基本的索引和切片:
arr[5]
arr[5:8]
arr[5:8] = 12
注意numpy數組跟python列表最大的不同是:數組切片是原始數組的視圖,也就是數據并不會被復制。
如果需要復制,需要顯式調用copy:arr[5:8].copy()
只有冒號表示選取整個軸:
arr[:]

數組的比較運算也是矢量化的,names == ‘Bob’將返回一個布爾型數組
“非”可以用!=或負號-
應用多個布爾條件,使用&、|

mask = (names == ‘Bob’) | (names == ‘Will’)
data[mask]

通過布爾型索引選取數組中的數據,將總是創建數據的副本。

按比例生成隨機數據:

帶比例數據示例
# 按比例生成隨機日期
np.random.choice(date_df['date'].astype(int),100,p=date_df['per'].tolist())
# 按比例生成隨機時間
np.random.choice(time_df['hour'].astype(int),100,p=time_df['radio'].tolist())
choice(a[, size, replace, p])

三、Matplotlib 可視化
使用繪圖主要是用于特征工程,發現暫時未知的因素對最終結果的影響
中文亂碼的解決:

#coding:utf-8
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標簽
plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號
#有中文出現的情況,需要u'內容'

Python繪圖鼻祖,
導入:

import matplotlib.pyplot as plt
plt.style.use('ggplot')
%matplotlib inline
import numpy as np

直方圖:

fig, ax = plt.subplots(figsize=(6,4))
ax.hist(df['petal width'], color='black');
ax.set_ylabel('Count', fontsize=12)
ax.set_xlabel('Width', fontsize=12)
plt.title('Iris Petal Width', fontsize=14, y=1.01)

散點圖:

fig, ax = plt.subplots(figsize=(6,6))
ax.scatter(df['petal width'],df['petal length'], color='green')
ax.set_xlabel('Petal Width')
ax.set_ylabel('Petal Length')
ax.set_title('Petal Scatterplot')

簡單線圖:

fig, ax = plt.subplots(figsize=(6,6))
ax.plot(df['petal length'], color='blue')
ax.set_xlabel('Specimen Number')
ax.set_ylabel('Petal Length')
ax.set_title('Petal Length Plot')

條形圖:

fig, ax = plt.subplots(figsize=(6,6))
bar_width = .8
labels = [x for x in df.columns if 'length' in x or 'width' in x]
ver_y = [df[df['class']=='Iris-versicolor'][x].mean() for x in labels]
vir_y = [df[df['class']=='Iris-virginica'][x].mean() for x in labels]
set_y = [df[df['class']=='Iris-setosa'][x].mean() for x in labels]
x = np.arange(len(labels))
ax.bar(x, vir_y, bar_width, bottom=set_y, color='darkgrey')
ax.bar(x, set_y, bar_width, bottom=ver_y, color='white')
ax.bar(x, ver_y, bar_width, color='black')
ax.set_xticks(x + (bar_width/2))
ax.set_xticklabels(labels, rotation=-70, fontsize=12);
ax.set_title('Mean Feature Measurement By Class', y=1.01)
ax.legend(['Virginica','Setosa','Versicolor'])

小提琴圖:

fig, ax = plt.subplots(2, 2, figsize=(7, 7))
sns.set(style='white', palette='muted')
sns.violinplot(x=df['class'], y=df['sepal length'], ax=ax[0,0])
sns.violinplot(x=df['class'], y=df['sepal width'], ax=ax[0,1])
sns.violinplot(x=df['class'], y=df['petal length'], ax=ax[1,0])
sns.violinplot(x=df['class'], y=df['petal width'], ax=ax[1,1])
fig.suptitle('Violin Plots', fontsize=16, y=1.03)
for i in ax.flat:
     plt.setp(i.get_xticklabels(), rotation=-90)
fig.tight_layout()

三、IPython

內?。?br> 任何變量后輸入?,可以展示此對象的通用信息
變量或方法后輸入??,可以展示源碼
配合*可以實現查找IPython命名空間,如np.*load*?

使用%run f.py運行f.py腳本

通過Ctrl - C中斷正在執行的代碼

魔術命令:
%timeit在任何語句前,檢測執行時間
使用?查看魔術命令選項,如%reset?
%quickref%magic,獲取魔術命令文檔

最近的兩個輸出結果分別保存在___

使用%cd 、%pwd執行常見操作

使用!執行shell命令

使用 %bookmark目錄書簽

表格打印

from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all" # 不必使用display或print也可以打印

from IPython.display import display, HTML

以下內容留待以后補充

四、Seaborn

使用pairplot查看不同特征維度pair下數據的空間分布狀況(散點圖和直方圖):

import seaborn as sns
sns.pairplot(df, hue="class") # hue控制區分顏色的變量名稱,這里用class列中的變量區別顏色

五、Scikit-learn

sklearn.metrics.accuracy_score(y_true, y_pred)

六、statsmodels
用于探索數據、估計模型,并運行統計校驗。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,197評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,415評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,104評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,884評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,647評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,130評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,208評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,366評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,887評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,737評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,478評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,174評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,586評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,827評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,608評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,914評論 2 372

推薦閱讀更多精彩內容