esproc vs python 4

1.計算每年同月份增長比

esproc


A
1=now()
2=file("C:\\Users\\Sean\\Desktop\\kaggle_data\\music_project_data\\sales.csv").import@t()
3=A2.groups(year(ORDERDATE):y,month(ORDERDATE):m;sum(AMOUNT):x)
4=A3.sort(m)
5=A4.derive(if(m==m[-1],x/x[-1]   -1,null):yoy)
6=interval@ms(A1,now())

A3:用ORDERDATE的年份和月份分組,並將該列命名爲y,m,同時計算該組的銷售量

group()函數分組但不彙總,groups分組同時彙總。

A4:按照月份m進行排序

A5:新增一列,如果月份等於前一行的月份,則計算增長比並賦值,否則賦值null,將該列命名爲yoy。

python:

import time

import numpy as np

import pandas as pd

s = time.time()

sales = pd.read_csv("C:\\Users\\Sean\\Desktop\\kaggle_data\\music_project_data\\sales.csv",sep='\t')

sales['ORDERDATE']=pd.to_datetime(sales['ORDERDATE'])

sales['y']=sales['ORDERDATE'].dt.year

sales['m']=sales['ORDERDATE'].dt.month

sales_g = sales[['y','m','AMOUNT']].groupby(by=['y','m'],as_index=False)

amount_df = sales_g.sum().sort_values(['m','y'])

yoy = np.zeros(amount_df.values.shape[0])

yoy=(amount_df['AMOUNT']-amount_df['AMOUNT'].shift(1))/amount_df['AMOUNT'].shift(1)

yoy[amount_df['m'].shift(1)!=amount_df['m']]=np.nan

amount_df['yoy']=yoy

print(amount_df)

e = time.time()

print(e-s)

pd.to_datetime(),轉換爲日期格式。新增加y和m列表示年和月。df.groupby(by,as_index)按照某個字段或者某幾個字段進行分組,其中參數as_index=False是否返回以組標籤爲索引的對象。df.sort_values()將新的dataframe按照月份和年份進行分組.新建一個數組,準備存放計算出來的同期增長比。df.shift(1)表示將原來的df下一行,即相對於當前行爲上一行,給該數組賦值爲增長比(當前行減上一行的值除以上一行的值),由於月份不同,所以將上一行與該行相同的月份賦值爲nan,最後將該數組賦值給df新增加的列yoy。

結果:

esproc

1550846990501100.png

python

1550846990650100.png


耗時
esproc0.007
python0.030

 

2. 計算1998年銷售額佔到一半的前 n 個客戶

esproc                     


A
1=now()
2=file("E:\\esproc\\esProc\\demo\\zh\\txt\\Contract.txt").import@t()
3=file("E:\\esproc\\esProc\\demo\\zh\\txt\\Client.txt").import@t().keys(ID).index()
4=A2.select(year(SellDate)==1998)
5=A4.groups(Client;sum(Amount):Amount)
6=A5.sort(-Amount)
7=A5.sum(Amount)/2
8=0
9=A6.pselect((A8=A8+Amount)>=A7)
10=A3.find@k(A6.to(A9).(Client)).(Name)
11=interval@ms(A1,now())

A3:T.keys(Ki,…),爲內表T定義鍵Ki,…。;T.index(n),爲序表T的鍵建立長爲n的索引表,n爲0或序表重置鍵時將清除索引表;n省略則自動選長度。如果需要多次根據鍵來查找數據,在建立了索引表之後可以提高效率。建立索引時假定記錄的主鍵唯一,否則出錯。

A4:篩選出1998年的交易記錄

A5:按照Client進行分組,同時計算交易量Amount之和

A6:按照Amount進行排序

A9:找到Amount累加到一半交易量的位置

A10:A.find(k),從排列/序表A中找到主鍵等於k的成員,有索引表則使用索引表。@k當參數k是序列時被認爲是鍵值序列,返回鍵值對應的A的成員。這裏是返回鍵ID的值等於A6.to(A9).(Client)的成員的Name字段序列。

python:

import time

import pandas as pd

import numpy as np

s = time.time()

contract_info=pd.read_csv('E:\\esproc\\esProc\\demo\\zh\\txt\\Contract.txt',sep='\t')

client_info = pd.read_csv('E:\\esproc\\esProc\\demo\\zh\\txt\\Client.txt',sep='\t',encoding='gbk')

contract_info['SellDate']=pd.to_datetime(contract_info['SellDate'])

contract_info_1998 = contract_info[contract_info['SellDate'].dt.year==1998]

contract_1998_g = contract_info_1998[['Client','Amount']].groupby(by='Client',as_index=False)

contract_sort = contract_1998_g.sum().sort_values(by = 'Amount',ascending=False).reset_index(drop=True)

half_amount = contract_sort['Amount'].sum()/2

sm=0

for i in range(len(contract_sort['Amount'])):

    sm+=contract_sort['Amount'][i]

    if sm>=half_amount:

        break

n_client = contract_sort['Client'].loc[:i]

client_info = client_info.set_index('ID')

print(client_info.loc[n_client]['Name'])

e = time.time()

print(e-s)

篩選出1998年的記錄

因爲這裏只用到了交易信息的Client和Amount字段,所以只選出這兩個字段並按照Client字段分組。df.sort_values(by,ascending),這裏是按照Amount進行倒序排序。

df.reset_index(drop)重建索引,drop=True表示丟掉原來的索引,否則把原來的索引當做一列插入。

求得所有交易額的一半的值,循環Amount字段,找到累加之和大於或等於交易額一半的位置。取Client字段0到該位置的值組成一個Series。

根據這個Series去client_info中找到對應的行的Name值。

結果:

esproc

1550846990763100.png

python

1550846988775100.png

 


耗時
esproc0.007
python0.016

 

3.找出1995年每個月銷售額都在前8名的銷售員

esproc


A
1=now()
2=file("E:\\esproc\\esProc\\demo\\zh\\txt\\SalesRecord.txt").import@t()
3=A2.groups(clerk_name:name,month(sale_date):month;sum(sale_amt):amount)
4=A3.group(month)
5=A4.(~.sort(-amount).to(8))
6=A5.isect(~.(name))
7=interval@ms(A1,now())

A3:按照clerk_name和月份month(sale_date)分組,同時將這兩個字段命名爲name和month,計算各組sale_amt的和,命名爲amount

A4:按照月份分組並進行求和。

A5:將amount按照倒序排序,並取前8名

A6: A.isect(),序列A成員可以爲序列,產生所有子序列都有的成員組成的新序列。這裏是求所有成員的交集。

python:

import time

import pandas as pd

import numpy as np

s = time.time()

sale_rec = pd.read_csv('E:\\esproc\\esProc\\demo\\zh\\txt\\SalesRecord.txt',sep='\t')

sale_rec['sale_date'] = pd.to_datetime(sale_rec['sale_date'])

sale_rec['m'] = sale_rec['sale_date'].dt.month

sale_rec_g = sale_rec.groupby(by=['clerk_name','m'],as_index=False).sum()

sale_month_g = sale_rec_g.groupby('m',as_index=False)

sale_set = set(sale_rec['clerk_name'].drop_duplicates().values.tolist())

for index,group in sale_month_g:

    group_topn = group.sort_values(by='sale_amt',ascending=False)[:8]

    sale_set = sale_set.intersection(set(group_topn['clerk_name'].values.tolist()))

print(list(sale_set))     

e = time.time()

print(e-s)

新增一列m表示月份

按照clerk_name,m進行分組,並求取sale_amt的和

按照m分組

初始化一個包含所有clerk_name的集合

循環分組,用初始集合與各個組的clerk_name一次求交集,並賦值給初始的集合,最終求得所有集合的交集。

結果:


結果耗時
esprocJenny,Steven0.010
pythonJenny,Steven0.023

 

4.找出修改過的記錄

esproc


A
1=now()
2=file("C:\\Users\\Sean\\Desktop\\kaggle_data\\music_project_data\\old.csv").import@t()
3=file("C:\\Users\\Sean\\Desktop\\kaggle_data\\music_project_data\\new.csv").import@t()
4=A2.sort(userName,date)
5=A3.sort(userName,date)
6=[A5,A4].merge@d(userName,date)
7=[A4,A5].merge@d(userName,date)
8=[A5,A4].merge@d(userName,date,saleValue,saleCount)
9=[A8,A6].merge@d(userName,date)
10=interval@ms(A1,now())

A4、A5:按照userName和date排序

A6: A.merge(xi,…) ,歸併計算A(i)|…,A(i)對[xi,…]有序,將多個序表/排列按指定字段xi有序合併,xi省略按主鍵合併,若xi省略且A沒有主鍵則按照r.v()合併。A(i)必須同構。@d選項,從A(1)中去掉A(2) &…A(n)中的成員後形成的新序表/排列,即求差集。新表與舊錶的差集即新增加的記錄。

A7:求舊錶與新表的差集,即舊錶中刪除的記錄。

A8:xi爲所有字段,得到新表中所有修改過的記錄包括新增的和修改的

A9:用所有修改的記錄與新增的記錄求差集得到修改的記錄。

python:

import time

import pandas as pd

import numpy as np

s = time.time()

old = pd.read_csv('C:\\Users\\Sean\\Desktop\\kaggle_data\\music_project_data\\old.csv',sep='\t')

new = pd.read_csv('C:\\Users\\Sean\\Desktop\\kaggle_data\\music_project_data\\new.csv',sep='\t')

old_delet_rec = pd.merge(old,new,how='left',on=['userName','date'])

delet_rec = old_delet_rec[np.isnan(old_delet_rec['saleValue_y'])][['userName', 'date', 'saleValue_x', 'saleCount_x']]

print('delet_rec')

print(delet_rec)

new_add_rec =  pd.merge(old,new,how='right',on=['userName','date'])

new_rec = new_add_rec[np.isnan(new_add_rec['saleValue_x'])][['userName', 'date', 'saleValue_y', 'saleCount_y']]

print('new_rec')

print(new_rec)

all_rec = pd.concat([old,new])

all_update_rec = all_rec.drop_duplicates(keep=False)

update_rec = all_update_rec[all_update_rec[['userName','date']].duplicated()]

print('update_rec')

print(update_rec)

e = time.time()

print(e-s)

首先merge(old,new,on=’left’)將舊錶左連接新表,新表中包含nan的行就是舊錶刪除的行,由於字段名一樣,所以python默認添加的後綴是_x,_y,刪除的記錄就是截取merge以後的前四個字段。

同理使用右連接,得到新表新增的行。

pd.concat([df1,df2])將舊錶和新表縱向連接,df.drop_duplicates(keep=False),刪除所有重複的行,得到兩張表所有不一樣的記錄,從中選出['userName','date']兩個字段相同的字段,即爲修改過的字段。

結果:

esproc

delet_rec

1550846988875100.png

new_rec

1550846988970100.png

update_rec

1550846989090100.png

python

1550846989189100.png


耗時
esproc0.003
python0.038

 

5. 計算出指定時間段內每天每種貨物的庫存狀態

題目介紹:stocklog.csv中的數據有四個字段分別是STOCKID貨物編號,DATE日期(不連續),QUANTITY出入庫數量,INDICATOR標緻,如果INDICATOR爲空表示入庫,ISSUE表示出庫。

數據如下:

1550846989284100.png

我們的目的是用這份數據分別計算出指定時間內各種貨物的庫存狀態,即STOCKID,貨物編號,DATE日期(連續的),OPEN開庫時數量,ENTER當天入庫數量,TOTAL最當天最大數量,ISSUE當天出庫數量,CLOSE閉庫時的數量。

esproc


AB
1=now()
2=file("C:\\Users\\Sean\\Desktop\\kaggle_data\\music_project_data\\stocklog.csv").import@t()
3=A2.select(DATE>=date(start)   && DATE<=date(end))
4=A3.groups(STOCKID,DATE;sum(if(INDICATOR=="ISSUE",QUANTITY,0)):ISSUE,sum(if(INDICATOR!="ISSUE",QUANTITY,0)):ENTER)
5=periods(start,end)
6for   A4.group(STOCKID)=A6.align(A5,DATE)
7
>b=c=0
8
=B6.new(A6.STOCKID:STOCKID,A5(#):DATE,c:OPEN,ENTER,(b=c+ENTER):TOTAL,ISSUE,(c=b-ISSUE):CLOSE)
9
>B8.run(ENTER=ifn(ENTER,0),ISSUE=ifn(ISSUE,0))
10
=@|B8
11=interval@ms(A1,now())

A3:選出指定日期內的數據,start和end是提前設置好的網格變量(在集算器的程序——網格參數處可以設置。)

A4:按照STOCKID和DATE分組,同時對各組進行計算,if(x,true,false),這裏是如果INDICATOR==ISSUE,if()函數等於QUANTITY的值,否則爲0,將此結果在該組中求和後添加到字段ISSUE,如果INDICATOR==ISSUE,if()函數等於0,否則爲QUANTITY的值,將此結果在該組中求和後添加到字段ENTER。最終得到每天每種物品的出入庫總數。

A5: periods可以生成時間序列

A6:循環分組

B6: P.align(A:x,y),x,y省略則以P當前記錄與A中成員對齊。通過關聯字段x 和 y 將P 的記錄按照A 對齊。對着排列P計算y的值,計算結果和A中的x的值相等則表示兩者對齊。這裏是當前產品的出入庫記錄與B5中的時間序列對齊。

B7:定義b,c兩個變量,b作爲OPEN字段的初始值,

B8:建立新表,其中STOCKID爲A6的STOCKID,將時間序列B5按順序插入新序表,作爲新字段DATE,c作爲OPEN字段,將B6中的ENTER字段當做現在ENTER字段,爲b賦值爲c+ENTER作爲TOTAL字段,將B6中的ISSUE字段當做現在ISSUE字段,最後把c賦值爲b-ISSUE作爲CLOSE字段。

B9: ifn(valueExp1, valueExp2) 判斷valueExp1的值是否爲空,若爲空則返回valueExp2,不爲空則返回該表達式的值。這裏就是將null填爲0.

B10:@表示當前格,這裏的意思是把結果不斷的彙總在當前格,最後得到結果。

python:

import time

import pandas as pd

import numpy as np

s=time.time()

starttime = '2015-01-01'

endtime = '2015-12-31'

stock_data = pd.read_csv('C:\\Users\\Sean\\Desktop\\kaggle_data\\music_project_data\\stocklog.csv',sep='\t')

stock_data['DATE']=pd.to_datetime(stock_data['DATE'])

stock_data = stock_data[stock_data['DATE']>=starttime]

stock_data = stock_data[stock_data['DATE']<=endtime]

stock_data['ENTER']=stock_data['QUANTITY'][stock_data['INDICATOR']!='ISSUE']

stock_data['ISSUE']=stock_data['QUANTITY'][stock_data['INDICATOR']=='ISSUE']

stock_g = stock_data[['STOCKID','DATE','ENTER','ISSUE']].groupby(by=['STOCKID','DATE'],as_index=False).sum()

stock_gr = stock_g.groupby(by='STOCKID',as_index = False)

date_df = pd.DataFrame(pd.date_range(starttime,endtime),columns=['DATE'])

stock_status_list = []

for index,group in stock_gr:

    date_df['STOCKID']=group['STOCKID'].values[0]

    stock_status = pd.merge(date_df,group,on=['STOCKID','DATE'],how='left')

    stock_status = stock_status.sort_values(['STOCKID','DATE'])

    stock_status['OPEN']=0

    stock_status['CLOSE']=0

    stock_status['TOTAL']=0

    stock_status = stock_status.fillna(0)

    stock_value = stock_status[['STOCKID','DATE','OPEN','ENTER','TOTAL','ISSUE','CLOSE']].values

    open = 0

    for value in stock_value:

        value[2] = open

        value[4] = value[2]+value[3]

        value[6] = value[4] - value[5]

        open = value[6]

    stock = pd.DataFrame(stock_value,columns = ['STOCKID','DATE','OPEN','ENTER','TOTAL','ISSUE','CLOSE'])

    stock_status_list.append(stock)

stock_status = pd.concat(stock_status_list,ignore_index=True)

print(stock_status)

e=time.time()

print(e-s)

pd.to_datetime(),將DATE字段轉換爲pandas的datetime類型。Pandas寫成這種形式(stock_data = stock_data[endtime>=stock_data['DATE']>=starttime])進行日期篩選是會報錯的,不支持同時計算,所以只能分兩次截取時間。

新建ENTER,ISSUE兩個字段,並按照INDICATOR是否是ISSUE判斷,如果是則將QUANTITY的值賦值給ISSUE,如果不是則將QUANTITY的值賦值給ENTER。

取到STOCKID,DATE,ENTER,ISSUE四個字段,並按照STOCKID,DATE進行分組,同時對各組求和,得到每一天每種貨物的出入庫記錄。

pd.date_range(starttime,endtime)生成一個starttime~endtime的Series,pd.DataFrame()將它生成爲一個dataframe(date_df)

將數據按照STOCKID進行分組

新建一個list,準備加入各個貨物的出入庫狀態。

循環各組,爲 date_df加入STOCKID列,生成包含DATE,STOCKID兩列的dataframe,pd.merge(df1,df2,on,how),將該dataframe與該組按照STOCKID,DATE,進行左連接,得到連續日期。

df.fillna(0)將df中的nan賦值爲0,

新增加三列OPEN,TOTAL,CLOSE並都賦值爲0.

將字段按照['STOCKID','DATE','OPEN','ENTER','TOTAL','ISSUE','CLOSE']順序,依次取出,並取得這些字段的值(類型是numpy.ndarray)。

初始化open=0

循環這個數組中的元素,'OPEN','ENTER','TOTAL','ISSUE','CLOSE'字段對應的值分別爲value[2], value[3], value[4], value[5], value[6],open賦值給value[2],TOTAL=OPEN+ENTER,CLOSE=TOTAL-ISSUE,再將close賦值給open作爲下一元素的value[2]。

最後將該數組轉換爲dataframe,得到這種貨物的出入庫狀態

將所有貨物的出入庫狀態都放入開始新建的list中

最後pd.concat([df1,df2,…,dfn],ignore_index)合併這些dataframe,忽略原來的索引,得到所有貨物的出入庫狀態。

結果:

esproc

1550846989432100.png

python

1550846989700100.png


耗時
esproc0.015
python0.089

 

6.計算每個人的起止值班時間

題目介紹:表duty記錄着值班情況,一個人通常會持續值班幾個工作日再換其他人,數據如下:

1550846989799100.png

我們的目的是根據duty表計算出每個值班的起止時間。

esproc


A
1=now()
2=file("C:\\Users\\Sean\\Desktop\\kaggle_data\\music_project_data\\duty.csv").import@t()
3=A2.group@o(name)
4=A3.new(name,~.m(1).date:begin,~.m(-1).date:end)
5=interval@ms(A1,now())

本例依舊簡單

A3:A.group(xi,…),將序列/排列按照一個或多個字段/表達式進行等值分組,結果爲組集構成的序列。@o表示分組時不重新排序,數據變化時才另分一組。

A4:A.new()根據序表/排列A的長度,生成一個記錄數和A相同,且每條記錄的字段值爲xi,字段名爲Fi的新序表/排列。這裏表示根據分組子集A3新建二維表,其中~.m(1)表示取各組首行,~.m(-1)表示取各組尾行。

python:

import time

import pandas as pd

import numpy as np

import random

s=time.time()

duty = pd.read_csv('C:\\Users\\Sean\\Desktop\\kaggle_data\\music_project_data\\duty.csv',sep='\t')

name_rec = ''

start = 0

duty_list = []

for i in range(len(duty)):

    if name_rec == '':

        name_rec = duty['name'][i]

    if name_rec != duty['name'][i]:

        begin = duty['date'].loc[start:i-1].values[0]

        end = duty['date'].loc[start:i-1].values[-1]

        duty_list.append([name_rec,begin,end])

        start = i

        name_rec = duty['name'][i]

begin = duty['date'].loc[start:i].values[0]

end = duty['date'].loc[start:i].values[-1]

duty_list.append([name_rec,begin,end])

duty_b_e = pd.DataFrame(duty_list,columns=['name','begin','end'])

print(duty_b_e)

e=time.time()

print(e-s)

說明:小編沒有找到pandas中不重新排序進行分組的方法,所以只能選擇這種笨方法,又因爲一直都是對比的pandas,所以也沒有用python自帶的IO讀取方式來完成此題。下面還是簡單介紹下代碼:

初始化name_rec用來保留name字段的值,strat用來保留截取位置,duty_list用來保存最後的結果。

創建一個循環,開始將數據中的第一個name的值賦值給name_rec,然後下一次循環,如果name_rec相同,則繼續。直到不相同了,取start~i-1位置的date的值,第0個賦值給begin,倒數第一個賦值給end,將name_rec,begin,end三個值放入初始化的duty_list中,然後將start賦值爲i緩存下來,更新name_rec爲當前的name值,進行下一次循環。

利用pd.DataFrame()生成dataframe。

結果:

esproc

1550846989953100.png

python

1550846990087100.png


耗時
esproc0.003
python0.020

 

7.統計各等級在各個項目上的人數合計

題目介紹:sports表中存放有各個項目(短跑,長跑,跳遠,跳高,鉛球)的成績(優秀,良好,及格,不及格),數據如下

1550846990160100.png

我們的目的是統計出各個等級在各個項目上的人數。

esproc


AB
1=now()
2=file("C:\\Users\\Sean\\Desktop\\kaggle_data\\music_project_data\\sports.csv").import@t()
3=[]
4for   A2.fname().to(2,)=A2.group(${A4})
5
=B4.new(A4:subject,~.${A4}:mark,~.count():count)
6
>A3=A3|B5
7=A3.pivot(subject;mark,count)
8=interval@ms(A1,now())

A3:初始化一個空序列,用來彙總統計的結果

A4:因爲sports表第一個字段是name,所以不用循環。循環各個項目的字段

B4:按照循環的這個字段進行分組

B5:新建一個表,該字段名作爲subject字段的值,該字段分組中的值作爲mark字段,分組中的成員數作爲count字段

B6:將每個項目的結果彙總到A3中

A7: A.pivot(g,…;F,V;Ni:N'i,…),以字段/表達式g爲組,將每組中的以F和V爲字段列的數據轉換成以Ni和N'i爲字段列的數據,以實現行和列的轉換。Ni缺省爲F中的不重複字段值,N'i缺省爲Ni。實現行列轉換,形成透視表。

python:

import time

import pandas as pd

import numpy as np

s = time.time()

sports = pd.read_csv('C:\\Users\\Sean\\Desktop\\kaggle_data\\music_project_data\\sports.csv',sep='\t')

subject_mark_cnt_list = []

for col in sports.columns[1:]:

    sports_g = sports.groupby(by=col,as_index=False).count()[[col,'name']]

    sports_g.rename(columns={'name':'count',col:'mark'},inplace=True)

    sports_g['subject']=col

    subject_mark_cnt_list.append(sports_g)

subject_mark_cnt = pd.concat(subject_mark_cnt_list,ignore_index=True)

subject_mark_count = pd.pivot_table(subject_mark_cnt[['subject','mark','count']],index = ['subject'],columns = 'mark',values = 'count')

print(subject_mark_count)

e = time.time()

print(e-s)

初始化subject_mark_cnt_list準備彙總循環的結果

循環除第一個字段的所有字段

df.groupby()按照該字段進行分組,統計分組中的成員數量,同時取當前的col這個字段和name字段。

df.rename(columns={})修改這個dataframe的列名

新增一列subject,並賦值爲當前的col值。

將這個dataframe放入初始化的subject_mark_cnt_list列表中。

pd.concat()將列表中的數據連接成新的dataframe

pd.pivot_table(data,index,columns,values)將其改爲透視表。

結果:

esproc

1550846990287100.png

python

1550846990386100.png


耗時
esproc0.004
python0.083

 

小結:本節我們計算了一些網上常見的題目,這些題目中多次用到了動態計算字段值,並進行賦值的操作,esproc很好的支持這一功能,大大簡化了代碼。而python不支持此功能,帶來了麻煩,並且esproc的~表示了當前記錄,省去了循環語句(其實仍是循環),python只能通過循環來完成。另外python中的merge函數不支持差集計算(或許其他函數支持),造成在第四例中特別麻煩。python pandas的dataframe結構是按列進行存儲的,按行循環時就顯得特別麻煩。


sales.csv
Contract.txt
Client.txt
SalesRecord.txt
old.csv
new.csv
stocklog.csv
duty.csv
sports.csv


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章