python狗狗年龄换算_Python之美——一只数据狗的笔记[长期更新]
兩年前咬咬牙跳了Matlab的坑,入手了Python,從此一發不可收的成了PY的重度依賴者。本人研究工作皆涉及大量的數據處理工作,PY和R作為數據分析的兩駕馬車,得其一者得天下。另外,我接觸的許多軟件皆比較小眾,每次在涉及二次開發時,很多都是Matlab之流不支持的,而PY又往往是官方指定接口。因此,PY作為程序界的黏合劑,實在是方便至極。
如今機器學習和深度學習之熱,再次炒熱了PY。當然,涉及到統計模型,R的功力還是更深的。很多前沿或者有一定深度的統計模型,在R中都能快速實現,但在PY中則沒有現成的package。因此,現在不得不承認,PY和R,各有千秋,要都熟稔才行。
寫此文,是為記錄一些靈感,供廣大PY愛好者,也供自己,學習與查閱。List形式的for in if else
爬到一組房價數據,但經緯度皆以'121.43247'的string形式存儲于DataFrame的一列中,且對于空缺值,以int形式的0或者float行駛的0.00填充。也就是說,該列存在多種數據格式,必須寫條件判斷才能循環。現需要將其進行修正提取,將'121.43247'提取為121.43247,而對于空值,統一以int形式的0填充。
于是,最低級的寫法出現了:
for jj in range(0, len(all_fangjia)):
if all_fangjia.loc[jj, 'len'] > 3:
all_fangjia.loc[jj, 'new_lat'] = all_fangjia.loc[jj, 'lat'].split('\'')[1]
all_fangjia.loc[jj, 'new_lon'] = all_fangjia.loc[jj, 'lon'].split('\'')[1]
該法思路清晰,但速度奇慢。對該列數據進行遍歷,先判斷該數據長度,如果大于3,說明是string形式的,然后再按照'''進行拆分(需要用\來轉義),選取第二個值進行提取。
思路是對的,但速度實在太慢了。于是,就要請出循環的list風格化了:
all_fangjia['new_lon'] = [var.split('\'')[1] if len(var) > 3 else 0 for var in all_fangjia['lon']]
all_fangjia['new_lat'] = [var.split('\'')[1] if len(var) > 3 else 0 for var in all_fangjia['lat']]
將代碼壓縮至了兩行,速度更是提升了幾十上百倍(具體提升量級沒算,但反正速度是飛快的了)。此法非常關鍵,掌握了對之后的數據處理效率大有提升。佛系空格分隔符的處理
在拿到某些奇葩的原始數據文件時,其不同列間的分隔不是傳統的',',而是奇葩的不規整的空格符,也就是說,某兩列用了三個空格符來分隔,某兩列則用了四個,甚至在一列中,某兩行用了2個空格分隔,某兩行則用了3個。。
對于這種佛系空格分隔符,一種處理方法就是用正則(re)表達式,而另一種非常簡單的方法,則是:
import pandas as pd
tem=pd.read_csv('583211-2017.out', delim_whitespace=True, engine='python')
即在熊貓包里面的read_csv中,設置delim_whitespace=True即可。字符串數據轉化為數字編號
比如有N個樣本,且存在一列專門對其類別進行標記,但標記用的全是字符串,如“大”、“中”、“小”。為了之后處理方便,需要將其變成0、1、2這種數字形式。這時就需要請出category類型來操作了。相關操作皆針對DataFrame格式實現。
obj_df["body_style"] = obj_df[“body_style"].astype('category')
obj_df["body_style_cat"] = obj_df["body_style"].cat.codes繪圖時批量改變所有字體大小
在利用matplotlib繪圖時,題目、坐標軸標簽、坐標軸名稱等等的字體大小都需要分別設置,非常麻煩,而下面的方法則可以批量一次性設置,修改起來也就隨之方便了。
應注意,如果有多個ax,則還需要再嵌套一層循環,先指向某一個ax.
import matplotlib.pyplot as plt
fig,ax=plt.subplots()
for item in ([ax.title, ax.xaxis.label, ax.yaxis.label] +
ax.get_xticklabels() + ax.get_yticklabels()):
item.set_fontsize(20)批量快速導入Oracle
做數據工作的,拿Python去接數據庫是非常常見的事情,而Oracle又是數據庫里面的老大哥。在此不介紹如何安裝接口包cx_Oracle,只介紹如何快速將大量數據一次性導入到Oracle中。
在沒Get到此技能之前,我都是一條條的往里面插入數據的,數據量小還好,一旦大起來,速度就奇慢無比了。
于是,便有了下面的思路:先打包,再導入:
#導入連接包
import cx_Oracle as oracle
db = oracle.connect('scott/redhat@192.168.223.138:1521/oracle.test')
#對待導入的數據進行處理
DFV = DFV.fillna('None')
DFV = DFV.values.tolist()
rows = []
for jj in range(len(DFV)):
# 轉list
row = (DFV[jj][0], DFV[jj][1], DFV[jj][2], DFV[jj][3], DFV[jj][4], DFV[jj][5], DFV[jj][6])
rows.append(row)
# 寫入數據
cr = db.cursor()
cr.prepare(
'insert into OTJ_WATERLINK_WK2 (linkid,fromnode,LONGITUDE,LATITUDE,GRIDID,ROADNAME,SECT) values (:1, :2, :3, :4, :5, :6, :7)')
cr.executemany(None, rows)
db.commit()
cr.close()
試過的都知道,速度杠杠的。再也不用擔心大型數據文件要花上好幾天才能擼進Oracle了。Groupby不支持的函數如何使用
數據處理里面的groupby簡直就是小白第一課也得學會的技能了。但groupby方便雖方便,很多時候卻不支持一些函數。比如,我要對某一列進行groupby,并對groupby后的數據塊內的另一列求分位數。這時:
train_day=data.groupby([‘TIMEID']).percentile()['GOSPEED']
卻顯示報錯,原因是groupby之后的數據塊不支持percentile()這個函數。
這時你想到的可能就是只能寫循環一步步進去了,不慌,groupby還給我們留了后路:
dg=data.groupby('TIMEID')
for a,b in dg:
z = np.percentile(b['GOSPEED'],5)
不只是percentile(),其他什么函數,都是可以這么玩的。速度雖然比groupby慢了一些,但比直接寫循環進去要快不少。指定區間,計算頻率
做頻率分布直方圖大家都會做,非常簡單,對離散型變量做頻數統計也很簡單,value_counts()函數就行,但如何對連續型變量按照指定的區間就行頻率統計呢?這里就需要用到cut和value_counts()的結合了。
cut函數可以將一個區間進行切割,返回切割后的小塊,再將其作為參數傳遞給value_counts()函數,就可以得出結果了。
xse = range(1, 5000, 1)
fanwei = list(range(0, 4500, 500))
fenzu = pd.cut(xse, fanwei, right=False)
print(fenzu.categories) # 分組區間,長度8
pinshu = fenzu.value_counts() # series,區間-個數讀入輸出文件的中文亂碼問題
這個問題大家幾乎都會遇到,解決方法也非常簡單,只要指定對了編碼,自然就不會亂碼了:
輸出CSV亂碼的話:
import codecs
FGIS.to_csv(‘FINALPOINT.csv',encoding="utf_8_sig",index=False)
導入CSV亂碼的話:
test=pd.read_csv(‘busgps_0309_0310_71.txt',encoding='gbk') #gbk不行就改成‘gb18030’
不論讀入導出啥文件,記住encoding不要亂,編碼就不會亂。數據結構化輸出及讀取
某個變量需要先保存好,下次再來直接讀取,而不是重新計算?MATLAB里面可以直接保存WORKPLACE里面的變量,PY怎么做呢?用pickle
import pickle
#導出
output = open('FWRON.pkl', 'wb')
pickle.dump(FWRON, output, -1)
output.close()
#讀取
pkl_file = open('FWRON.pkl', 'rb')
FWRON = pickle.load(pkl_file)
pkl_file.close()多版本PY的管理
由于不同的包可能在不同版本下才能生存,所以一臺電腦有好幾個PY很正常,而解決他們的共生問題也是十分的頭疼。比如我的電腦里就有三個版本的PY(我也不知道怎么這么多)。。其中,conda管理的兩個:2.7和3.4;還有在系統下的一個3.6。
對于用conda來管理的各種版本,則可以使用conda來進行切換,相對要簡單很多。切換完畢后,就可以在該版本下進行包的安裝管理。強烈建議用conda而非pip來安裝package。
conda info --envs
source activate python34 # conda activate geo_env
conda install -c conda-forge osmnx
sudo pip install [package_name] --upgrade
而我之前沒用conda之前,一直都在用系統的3.6。所以,很多時候我還是要對3.6系統下的環境做配置。下面記錄了更新pip以及利用pip指定版本安裝包的過程。注意全程加上python3來指代PY3的版本(我默認是用的2.7),以及,記得加上--user,否則會一直報錯[Errno 13] Permission denied。
curl https://bootstrap.pypa.io/get-pip.py | python3 - --user
python3 -m pip install --user osmnx
PY版本是非常頭疼的事情。最好的辦法是完全基于conda來配置自己的環境。不要和我一樣,多個PY版本分散在各個地址,配置起來非常麻煩。一行代碼解決兩個字符串組的匹配
近期在做特征的時候,需要對異常站點進行清洗。其間遇到一個問題,記錄如下:
有一個list A,里面存儲著系列表征站點錯誤的關鍵詞,如“關閉”、“不開放”、“非運營”。
另外有一個list B,里面存儲著所有站點的名稱,如“虹橋站”、“上海南站”、“五角場站”。
在list B中,有部分站點是出錯的,這些站點會在名稱中進行標記,如虹橋站出錯了,該站的名字會改成“(關閉)虹橋站”,當然,也可能改成“(不開放)虹橋站”。
現在需要把list B中所有的出錯站點找出來。
問題復述一遍就是:以list A中的每一個元素為關鍵詞,對list B中每一個元素進行匹配,如果list B中某個元素包含list A中的任意一個元素,則將list B中的該元素標記為FALSE。
當然寫循環,用 A in B,是肯定可以做的。但是,有沒有更簡潔的寫法呢?
嘗試了一下,是有的:
Wrong_list=['關閉','不開放','非運營']
Test_list=['虹橋站','(不開放)虹橋站']
Bool_result=[any(list(wrongs in var for wrongs in Wrong_list)) for var in Test_list]
最后返回:Bool_result=[FALSE, TRUE]
需要注意:
1)兩個for的順序:先寫for wrongs in Wrong_list,再寫for var in Test_list,最終得出的Bool_result才是針對Test_list的。
2)list在此的作用:將generator object 轉化為bool格式。
3)any在此的作用:表示“只要有一即可”。
4)括號在此的作用:為any提供計算優先級。applymap與匿名函數
常常會遇到需要對矩陣中的所有數值執行某個函數的情況,但又懶得寫def,這時候就可以祭出applymap大殺器了:
DF.applymap(lambda x: -(x * math.log(x)) if x > 0 else np.nan)
這句話的功能是,對DF這個矩陣里面的每一個大于0的值,執行-(x * math.log(x))的運算,如果該值小于0,則置為nan。
要注意applymap和apply的區別。后者是對行或列進行處理:
DF.apply(lambda x: sum(x != 0), axis=1)
如上面的代碼,則是返回每一行(axis=1)中不等于0的個數。去除DF中含有重復名字的列
有時候MERGE多了,難免會出現一個DF里面有好一些列完全一致——內容一致,列名也一致。這在某些時候,列名一致是容易出錯的,最好需要及時清理他們。清理方法是:
DF=DF.ix[:,~DF.columns.duplicated()]
一句話就可以去重啦,非常的利索有沒有。選取groupby后某列最小值對應的行
做數據處理的時候常常會遇到這樣的問題:對于一個DF,我們按照A、B兩列進行groupby后,選取每個group內C列最小值所對應的行并返回。
DF1=DF.loc[DF.groupby(['A','B'])['C'].idxmin()]
原理其實很簡單,用到了一個idxmin(),可以返回最小值對應的行索引。根據列類型選取列
很多時候如果列很多,而且我們需要選取特定類型的列進行變化。比如,在做線性回歸時,把所有BOOL類型的列改為0,1類型:
Exposure_DATA_NEW.loc[:, Exposure_DATA_NEW.dtypes == np.bool] = Exposure_DATA_NEW.loc[:,Exposure_DATA_NEW.dtypes == np.bool].astype(int)
這里用到了DF.dtypes == np.bool,來對列進行圈取。對每一個group進行NA均值填充
很多時候我們在做缺失值填充時,會需要先groupby,然后再對每一個group,計算該group的均值,并填充至該group的缺失值處:
Exposure_DATA["surfacewid"] = Exposure_DATA.groupby("rank_artclass")["surfacewid"].transform(
lambda x: x.fillna(x.mean()))CX_ORACLE的中文亂碼問題
在利用CX_ORACLE讀入數據時,不做處理,中文就會直接跳問號。需要在程序前加上:
import os
import sys
reload(sys)
sys.setdefaultencoding("gbk")
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8'去除列名,豎向疊加
npCombined_Net = np.concatenate([metro_route.as_matrix(), tem_null.as_matrix()], axis=0)
metro_route = pd.DataFrame(npCombined_Net, columns=metro_route.columns)Brew的安裝與運用
如何安裝:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
安裝完還找不到怎么辦:
export PATH=/usr/local/bin:$PATH
利用brew來安裝一個mysql:
brew install mysql矩陣的去方向groupby
在做出一個網絡邊矩陣時,常常會出現這樣的情況,我們需要的是無向的,但邊矩陣卻是有向的。即,假如矩陣一共三類,‘FROM’,‘TO’,‘VALUE’,我們認為FROM 3 TO 1和FROM 1 TO 3是一類的,因此,我們需要把FROM 3 TO 1和FROM 1 TO 3的VALUE 求均值。怎么做:
edge_centrality_nodir = pd.DataFrame(np.sort(edge_centrality[['from', 'to']], axis=1), edge_centrality.index, edge_centrality[['from', 'to']].columns)
edge_centrality_nodir['bc'] = edge_centrality['bc']
edge_centrality_nodir_f = edge_centrality_nodir.groupby(['from', 'to']).mean()['bc'].reset_index()
其中edge_centrality為有向矩陣,edge_centrality_nodir為矩陣無向化,edge_centrality_nodir_f為最終groupby后的結果。矩陣無向化的過程,實際是對每一行進行重新排序的過程。注意把from 和 to兩列單獨拎出來。繪圖label只顯示兩位小數
from matplotlib.ticker import FormatStrFormatter
fig, ax = plt.subplots()
ax.yaxis.set_major_formatter(FormatStrFormatter('%.2f'))range()不能產生float??
不要慌,用arange:
import numpy as np
np.arange(1,10,0.1)DF某一列中是否包含某個字符
比如要判斷DF的某一列中是否含有“A”這個字符:
DF['Names'].str.contains('A')
那如果要把“A”這個字符替換成“-”怎么辦呢:
DF['Names'].str.replace('A','-')
真心的方便呀。比如你在處理時間字段時,有些直接就成“XX年XX月XX日”這種格式了,這時你為了轉化為datetime,首先就是把“年”、“月”、“日”都替換成“-”。多個DF的merge
譬如你有N個DF,這些DF具有相同的KEY列,你需要把他們按照這個KEY列一并MERGE起來。怎么做?
首先把需要MERGE的放在dfs這個list里面,然后用reduce來解決:
from functools import reduce
dfs = [ord_count, ord_real_mn, order_coup_mn, order_final_mn]
df_final = reduce(lambda left, right: pd.merge(left, right, on='authid_s'), dfs)
我們的宗旨是:代碼這東西,多寫一行都是在浪費生命。list以及numpy的repeat
在構造全序列時,常常需要對一個list進行重復,重復又分為兩種:[1,2,3]--->[1,1,2,2,3,3]
[1,2,3]--->[1,2,3,1,2,3]
需要注意,在python中這兩種寫法是截然不同的。假設我們需要構建三列,第一列為站點ID,第二列為每一天,第三列為每一個小時:
timerange = pd.DataFrame(pd.date_range(start='1/1/2017', end='12/31/2017', freq='D'))
timerange[0] = timerange[0].astype(str)
full_time_range = pd.DataFrame({'SHOPSEQ': np.repeat(list(shop_need_seq), 365 * 24),
'date': list(np.repeat(list(timerange[0]), 24)) * len(shop_need_seq),
'HOUR0': list(range(1, 25, 1)) * len(shop_need_seq) * 365})DF中的mean和count是怎么對待NAN的?
The internalcount()function will ignoreNaNvalues, and so willmean(). The only point where we getNaN, is when the only value isNaN. Then, we take the mean value of an empty set, which turns out to beNaN
即:默認情況下,DF的 count()和mean()函數都是自動忽視NAN的,在計算均值時,除非你的所有數都是NAN,才會出現NAN的結果。reshape(-1)?-1是什么size?
這是非常能提現python之懶的一個點,懶得什么境界呢?就是你只知道變形后的列數,懶得算變形后的行數,你就拿-1代替好了。。:
假如是這么一個array:
z = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]])
直接-1之后,變成12行1列的矩陣:
z.reshape(-1)
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
我想把他變成2列,但我懶得算有幾行:在行數那里寫-1,系統自動幫你補全為6行:
z.reshape(-1, 2)
array([[ 1, 2],
[ 3, 4],
[ 5, 6],
[ 7, 8],
[ 9, 10],
[11, 12]])Datetime格式的LIST相減并返回秒
DT格式直接相減,得到的格式是非秒的,因此需要再做一個匿名函數轉化:
train['check_trip_duration'] = (train['dropoff_datetime'] - train['pickup_datetime']).map(lambda x: x.total_seconds())多索引排序后的重索引
在做多索引排序后,常常遇到的一個問題是,我們想按照排序后的結果,對每個組內的數據按照排序后的結果進行索引重定義:
DF=DF.sort_values(['A','B'],ascending=True)
DF=DF.groupby('A').apply(lambda x: x.reset_index(drop=True)).drop('A',axis=1).reset_index()
第一句是多索引排序,排序完成后,我們先對GROUP后的結果做一個匿名函數進行reset_index,這時DF的索引變成A+range(0,len(A))的格式。注意,在進行再重索引時,務必先將A刪去,否則會出現兩列A而無法進行。繪圖時解決中文亂碼、批量設置字體大小以及擴大圖像可容納的點位
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams['agg.path.chunksize'] = 10000
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用來正常顯示中文標簽
plt.rcParams['axes.unicode_minus'] = False # 用來正常顯示負號
plt.rcParams.update({'font.size': 22})
這幾句在做中文圖、整體修改圖的字體大小的時候可以加上。APPLY函數
當需要以DF格式的兩列為參數,做一些函數關系與條件判斷的處理的時候,通過先構建函數再APPLY的方式,可以避免逐行循環,提高效率。
比如我想以某DF的某一列為參數,對另一列中的string進行切片,并需要滿足一些規則:
def eachrowsplit(index0, strr):
if index0 - 3 >= 0:
return strr[index0 - 3:index0]
elif index0 == 2:
return strr[index0 - 2:index0]
elif index0 <= 1:
return np.nan
else:
return np.nan
在定義好這個函數后,我們再調用APPLY,將函數APPLY到對應的兩列上:
Baishitong_station1['price_final'] = Baishitong_station1.apply(lambda row: eachrowsplit(row['Index_yuan'], row['price']), axis=1)對比兩串字符串的相似性
目前有許多算法來界定字符串的相似性。在這里介紹一種,可以無序判斷的,即“廣東深圳”與“深圳廣東”他認為相似度是100%:
def similar(a, b):
# return SequenceMatcher(None, a, b).ratio()
return fuzz.token_sort_ratio(a, b) / 100
然后對DF的兩列進行對比:
Baishitong_station1['simi_name'] = Baishitong_station1.apply(lambda row: similar(row['name'], row['parkName']), axis=1)Groupby+values_count+stacked bar plot
兩行代碼搞定,感謝unstack大法,還可以做篩選
tem = ALL_DATA_RAW.groupby(['app', 'time_diff_int']).size()
tem[(tem > 100) & (tem < 100000)].unstack(fill_value=0).plot(kind='bar', stacked=True)Groupby后返回第一行和最后一行且不skip nan
依舊是一行代碼搞定
ALL_DATA_RAW.groupby('parkSeq').nth([0, -1])
這里不采用.first()的原因是.nth()是不會忽視NAN的:
“The difference between them is how they handle NaNs, so.nth(0)will return the first row of group no matter what are the values in this row, while.first()will eventually return the firstnotNaNvalue in each column.”distplot+groupby怎么實現
g = sns.FacetGrid(ALL_DATA_RAW_1, hue="app", palette="Set1", legend_out=False)
g = (g.map(sns.distplot, "ratio", hist=True)).add_legend()
distplot是不帶hue,但可以借助FacetGrid的hue來實現groupby的繪制:旋轉矩陣
pd.pivot_table(tem, values='PFloor_Area', index=['ParkSeq'], columns='Land_Category').reset_index()PYCHARM的全局搜索快捷鍵失效
CTRL+SHIFT+F是全局搜索,不要用雙shift,搜不全的。
但是CTRL+SHIFT+F同時還是微軟自帶的簡繁切換快捷鍵,需要先把這個關了:多維轉一維
df2=FSEMF.groupby([‘day','m5']).agg({'volume':'sum'}).unstack().fillna(-1).stack().reset_index()計算連續時序長度
# Build dataframw
tem = pd.DataFrame({'ID': np.repeat(range(1, 10), 31),
'Date': list(pd.date_range('2020-03-01', '2020-03-31', freq='D')) * 9})
tem1 = tem.sample(200)
# Sort
tem1 = tem1.sort_values(by=['ID', 'Date']).reset_index(drop=True)
# Diff
tem1['Diff'] = tem1.groupby('ID').diff()['Date'].dt.days
tem1.loc[tem1['Diff'] != 1, 'Diff'] = np.nan
tem1['CUMSUM'] = tem1.Diff.groupby(tem1.Diff.isna().cumsum()).cumsum()
# Max
final = tem1.groupby(['ID']).max()['CUMSUM'].reset_index()
final['CUMSUM'] = final['CUMSUM'] + 1
總結
以上是生活随笔為你收集整理的python狗狗年龄换算_Python之美——一只数据狗的笔记[长期更新]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python3 next_对Python
- 下一篇: 华为路由器固件_【卖萌推荐】路由器推荐第