對(duì)于非連續(xù)數(shù)據(jù)集,數(shù)據(jù)可視化時(shí)候需要每七天一個(gè)采樣點(diǎn)。要求是選擇此前最新的數(shù)據(jù)作為當(dāng)日的數(shù)據(jù)展示,譬如今天是2019-06-18,而數(shù)據(jù)集里只有2019-06-15,那就用2019-06-15的數(shù)據(jù)作為2019-06-18的數(shù)據(jù)去描點(diǎn)。
每七天一個(gè)采樣點(diǎn),會(huì)使得每天展示所選的數(shù)據(jù)都會(huì)有所不同。當(dāng)時(shí)間往后推移一天,日期為2019-06-19,那么最新數(shù)據(jù)點(diǎn)從2019-06-19開(kāi)始,第二個(gè)就是2019-06-12。這里就需要一個(gè)算法來(lái)快速的根據(jù)當(dāng)前日期去選出(填充)一系列數(shù)據(jù)供數(shù)據(jù)可視化之用。
一個(gè)非常直接的實(shí)現(xiàn)方法:
先生成一串目標(biāo)時(shí)間序列,從某個(gè)開(kāi)始日到今天為止,每七天一個(gè)日期。
把這些日期map到數(shù)據(jù)集的日期, Eg. {“2019-06-18”:“2019-06-15”…} 。
把map到的數(shù)據(jù)抽出來(lái)用pd.concat接起來(lái)。
代碼如下:
target_dates = pd.date_range(end=now, periods=100, freq="7D")
full_dates = pd.date_range(start, now).tolist()
org_dates = df.date.tolist()
last_date = None
for d in full_dates:
if d in org_dates:
date_map[d] = d
last_date = d
elif last_date is not None:
date_map[d] = last_date
else:
continue
new_df = pd.DataFrame()
for td in target_dates:
new_df = pd.concat([new_df, df[df["date"]==date_map[td]])
這樣的一個(gè)算法處理一個(gè)接近千萬(wàn)量級(jí)的數(shù)據(jù)集上大概需要十多分鐘。仔細(xì)檢查發(fā)現(xiàn),每一次合并的dataframe數(shù)據(jù)量并不小,而且總的操作次數(shù)達(dá)到上萬(wàn)次。
所以就想如何避免高頻次地使用pd.concat去合并dataframe。
最終想到了一個(gè)巧妙的方法,只需要修改一下前面的第三步,把日期的map轉(zhuǎn)換成dataframe,然后和原始數(shù)據(jù)集做merge操作就可以了。
target_dates = pd.date_range(end=now, periods=100, freq="7D")
full_dates = pd.date_range(start, now).tolist()
org_dates = df.date.tolist()
last_date = None
for d in full_dates:
if d in org_dates:
date_map[d] = d
last_date = d
elif last_date is not None:
date_map[d] = last_date
else:
continue
#### main change is from here #####
date_map_list = []
for td in target_dates:
date_map_list.append({"target_date":td, "org_date":date_map[td]})
date_map_df = pd.DataFrame(date_map_list)
new_df = date_map_df.merge(df, left_on=["org_date"], right_on=["date"], how="inner")
改進(jìn)之后,所有的循環(huán)操作都在一個(gè)微數(shù)量級(jí)上,最后一個(gè)merge操作得到了所有有用的數(shù)據(jù),運(yùn)行時(shí)間在5秒左右,大大提升了性能。
補(bǔ)充:Pandas DataFrames 中 merge 合并的坑點(diǎn)(出現(xiàn)重復(fù)連接鍵)
在我的實(shí)際開(kāi)發(fā)中遇到的坑點(diǎn),查閱了相關(guān)文檔 總結(jié)一下
left = pd.DataFrame({'A': [1, 2], 'B': [2, 2]})
right = pd.DataFrame({'A': [4, 5, 6], 'B': [2, 2, 2]})
result = pd.merge(left, right, on='B', how='outer')
警告:在重復(fù)鍵上加入/合并可能導(dǎo)致返回的幀是行維度的乘法,這可能導(dǎo)致內(nèi)存溢出。在加入大型DataFrame之前,重復(fù)值。
檢查重復(fù)鍵
如果知道右側(cè)的重復(fù)項(xiàng)DataFrame但希望確保左側(cè)DataFrame中沒(méi)有重復(fù)項(xiàng),則可以使用該 validate='one_to_many'參數(shù),這不會(huì)引發(fā)異常。
pd.merge(left, right, on='B', how='outer', validate="one_to_many")
# 打印的結(jié)果:
A_x B A_y
0 1 1 NaN
1 2 2 4.0
2 2 2 5.0
3 2 2 6.0
參數(shù):
validate : str, optional
If specified, checks if merge is of specified type.
“one_to_one” or “1:1”: check if merge keys are unique in both left and right datasets.
“one_to_many” or “1:m”: check if merge keys are unique in left dataset.
“many_to_one” or “m:1”: check if merge keys are unique in right dataset.
“many_to_many” or “m:m”: allowed, but does not result in checks.
官方文檔連接:
Pandas文檔中提及 merge
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
您可能感興趣的文章:- Python基礎(chǔ)之pandas數(shù)據(jù)合并
- python-pandas創(chuàng)建Series數(shù)據(jù)類型的操作
- Python數(shù)據(jù)分析之pandas函數(shù)詳解
- python基于Pandas讀寫MySQL數(shù)據(jù)庫(kù)
- pandas讀取excel時(shí)獲取讀取進(jìn)度的實(shí)現(xiàn)
- pandas中.loc和.iloc以及.at和.iat的區(qū)別說(shuō)明
- 淺談Pandas dataframe數(shù)據(jù)處理方法的速度比較
- 解決使用pandas聚類時(shí)的小坑
- 詳細(xì)介紹在pandas中創(chuàng)建category類型數(shù)據(jù)的幾種方法
- python中pandas.read_csv()函數(shù)的深入講解
- pandas 顛倒列順序的兩種解決方案
- pandas調(diào)整列的順序以及添加列的實(shí)現(xiàn)
- pandas快速處理Excel,替換Nan,轉(zhuǎn)字典的操作
- Python基礎(chǔ)之教你怎么在M1系統(tǒng)上使用pandas