一場pandas與SQL的巔峰大戰(四)

本文目錄:

資料準備

SQL計算周同比和日環比

pandas計算周同比和日環比

在之前的三篇系列文章中,我們對比了pandas和SQL在資料方面的多項操作。

具體來講,第一篇文章

一場pandas與SQL的巔峰大戰

涉及到

資料檢視

去重計數

條件選擇

合併連線

分組排序

等操作。

第二篇文章

一場pandas與SQL的巔峰大戰(二)

涉及

字串處理

視窗函式

行列轉換

型別轉換

等操作。

第三篇文章

一場pandas與SQL的巔峰大戰(三)

圍繞日期操作展開,主要討論了

日期獲取

日期轉換

日期計算

等內容。

本篇文章一起來學習常見的應用例項:

如何在SQL和pandas中計算同環比

。將分別在MySQL,Hive SQL和pandas中用多種方案來實現樣例資料日環比,周同比計算。

◆ ◆ ◆ ◆ ◆

資料準備

同比和環比本身都是相對的概念。同比是指和上個週期內同期資料的對比,可以是年同比,月同比,周同比等。環比是指連續兩個統計週期內資料的對比,可以是日環比,周環比,月環比等。工作中常見的是周同比和日環比。周同比即當天和上週同一天資料的變化百分比,日環比即當天和昨天資料的變化百分比。本文也主要計算周同比和日環比。資料概況如下,是隨機生成的兩個月的銷售額資料。

資料樣例如下所示,從左到右依次表示,id,日期,當日銷售額,資料週期從2019-11-01到2019-12-31。公眾號後臺回覆“

對比四

”,即可獲取本文全部程式碼和資料。

一場pandas與SQL的巔峰大戰(四)

pandas載入資料

import pandas as pdimport datetimeorderamt = pd。read_excel(‘orderamt。xlsx’)orderamt。head()

MySQL載入資料

一場pandas與SQL的巔峰大戰(四)

和前面的文章類似,使用navicate把我準備的orderamt。sql匯入資料庫中即可。

Hive載入資料

CREATE TABLE `t_orderamt`(  `id` int,   `dt` string,   `orderamt` float)row format delimited fields terminated by ‘,’stored as textfile;SQLload data local inpath ‘orderamt。txt’ overwrite into table t_orderamt;select * from t_orderamt limit 20;

一場pandas與SQL的巔峰大戰(四)

按照上面的程式碼建表,然後把orderamt。txt的內容載入到表中即可,最終資料如上圖所示。

SQL計算周同比和日環比

我們關注的是周同比和日環比,其實就是關注當天,昨天,7天前的資料,然後相應的算一下變化的百分比即可。思路一:自關聯,關聯條件是日期差分別是1和7,分別求出當天,昨天,7天前的資料,用三列形式展示,之後就可以進行作差和相除求得百分比。思路二:不進行關聯,直接查詢當前日期前一天和前七天的資料,同樣以3列的形式展示。

來看一下SQL程式碼:

一場pandas與SQL的巔峰大戰(四)

上面程式碼中我們關聯了兩次,條件分別是日期相差1天和日期相差7天。關聯不上的則留空。

再來看另一種寫法:

一場pandas與SQL的巔峰大戰(四)

這種寫法巧妙地使用表的別名查詢出了前1天和前7天的金額,效果和第一種寫法一樣,不過這種寫法可能小眾一點。

回到上面的思路2,我們在前面的學習中知道,Hive中有視窗函式支援查詢當前行前n行的資料,可以實現同樣的效果。程式碼如下:

select *, lag(orderamt, 1) over(order by dt) ld_amt, lag(orderamt, 7) over(order by dt) lw_amtfrom t_orderamt;

一場pandas與SQL的巔峰大戰(四)

以上面的程式碼為基礎,稍加修改,增加計算百分比的程式碼,就可以分別得到周同比和日環比。

——第一段修改select a。*, concat(round(((a。orderamt - b。orderamt) / b。orderamt) * 100,2), ‘%’) as ld_pct,concat(round(((a。orderamt - c。orderamt) / c。orderamt) * 100,2), ‘%’) as lw_pctfrom t_orderamt aleft join t_orderamt bon DATEDIFF(a。dt, b。dt) = 1left join t_orderamt con DATEDIFF(a。dt, c。dt) = 7order by dt;——第二段修改select b。id, b。dt, b。orderamt,concat(round(((b。orderamt - ld_amt) / ld_amt) * 100,2), ‘%’) as ld_pct,concat(round(((b。orderamt - lw_amt) / lw_amt) * 100,2), ‘%’) as lw_pctfrom(select *, (select orderamt from t_orderamt where dt = date_add(a。dt, interval -1 day)) ld_amt,(select orderamt from t_orderamt where dt = date_add(a。dt, interval -7 day)) lw_amtfrom t_orderamt a) b;——第三段修改select b。id, b。dt, b。orderamt,concat(round(((b。orderamt - ld_amt) / ld_amt) * 100,2), ‘%’) as ld_pct,concat(round(((b。orderamt - lw_amt) / lw_amt) * 100,2), ‘%’) as lw_pctfrom(select *, lag(orderamt, 1) over(order by dt) ld_amt, lag(orderamt, 7) over(order by dt) lw_amtfrom t_orderamt) b

一場pandas與SQL的巔峰大戰(四)

一場pandas與SQL的巔峰大戰(四)

pandas計算周同比和日環比

在pandas中,我們同樣首先按照上面的兩種思路進行計算。

方法一

:日期關聯的方法

import pandas as pdimport datetimeorderamt = pd。read_excel(‘orderamt。xlsx’)#orderamt[‘dt’] = orderamt[‘dt’]。apply(lambda x: datetime。datetime。strptime(x, ‘%Y-%m-%d’))#為了便於日期加減,將dt轉換為datetime64[ns]的格式,視情況執行該句#分別構造兩個dateframe用於關聯orderamt_plus_1 = orderamt。copy()orderamt_plus_7 = orderamt。copy()orderamt_plus_1[‘dt’] = orderamt_plus_1[‘dt’] + datetime。timedelta(days=1)orderamt_plus_7[‘dt’] = orderamt_plus_7[‘dt’] + datetime。timedelta(days=7)orderamt_1 = pd。merge(orderamt, orderamt_plus_1, on=[‘dt’],how=‘left’)orderamt_1_7 = pd。merge(orderamt_1, orderamt_plus_7, on=[‘dt’],how=‘left’)orderamt_all = orderamt_1_7[[‘id_x’, ‘dt’, ‘amt_x’, ‘amt_y’, ‘amt’]]

一場pandas與SQL的巔峰大戰(四)

方法二

:應用shift函式,直接選取前面n行的方法:

orderamt = pd。read_excel(‘orderamt。xlsx’)orderamt[‘ld_amt’] = orderamt[‘amt’]。shift(1)orderamt[‘lw_amt’] = orderamt[‘amt’]。shift(7)orderamt

一場pandas與SQL的巔峰大戰(四)

這樣得到的效果和SQL方式是一致的。如果要計算百分比,同樣是稍微加工即可:

#接方法一程式碼orderamt_all[‘ld_pct’] = (orderamt_all[‘amt_x’] - orderamt_all[‘amt_y’]) / orderamt_all[‘amt_y’]orderamt_all[‘lw_pct’] = (orderamt_all[‘amt_x’] - orderamt_all[‘amt’]) / orderamt_all[‘amt’]orderamt_all

一場pandas與SQL的巔峰大戰(四)

#接方法二程式碼orderamt[‘ld_pct’] = (orderamt[‘amt’] - orderamt[‘ld_amt’]) / orderamt[‘ld_amt’]orderamt[‘lw_pct’] = (orderamt[‘amt’] - orderamt[‘lw_amt’]) / orderamt[‘lw_amt’]orderamt

一場pandas與SQL的巔峰大戰(四)

在pandas中,還有專門的計算同環比的函式pct_change。

方法三

:使用pandas的pct_change()函式計算

orderamt = pd。read_excel(‘orderamt。xlsx’)orderamt[‘ld_pct’] = orderamt[‘amt’]。pct_change()orderamt[‘lw_pct’] = orderamt[‘amt’]。pct_change(7)orderamt

一場pandas與SQL的巔峰大戰(四)

上面的程式碼中,我們都沒有用百分比的形式保留結果,這裡提供一種方式。

#接方法三,方法一二類似orderamt[‘ld_pct’] = orderamt[‘ld_pct’]。apply(lambda x: format(x, ‘。2%’))orderamt[‘lw_pct’] = orderamt[‘lw_pct’]。apply(lambda x: format(x, ‘。2%’))orderamt

一場pandas與SQL的巔峰大戰(四)

至此,我們完成了SQL和pandas中對於周同比和日環比計算的過程。

◆ ◆ ◆ ◆ ◆

小結

本篇文章中,我們使用SQL和pandas的多種方法對常見的周同比和日環比進行計算。在同樣的思路指導下,SQL和pandas實現的方式各有特色,程式碼並不複雜,但值得細細品味。公眾號後臺回覆“

對比四

”可以獲取本文pdf版本,程式碼,資料等進行實戰,希望對你有所幫助。

一場pandas與SQL的巔峰大戰(四)

一場pandas與SQL的巔峰大戰(四)