2017-10-13 39 views
1

triggers柱的樣品中我DASK數據幀如下所示:不兼容性在DASK適用的和熊貓dataframes

0 [Total Traffic, DNS, UDP] 
1     [TCP RST] 
2    [Total Traffic] 
3     [IP Private] 
4      [ICMP] 
Name: triggers, dtype: object 

我想創建上述陣列的一個熱點編碼版本(放例如,針對第1行中的DNS列的1),通過執​​行以下操作。 pop_triggers包含triggers的所有可能值。

for trig in pop_triggers: 
    df[trig] = df.triggers.apply(lambda x: 1 if trig in x else 0) 

然而,Total TrafficDNS等列中的所有包含的相關值的值0和1不。當我將它複製到熊貓數據框中並執行相同的操作時,它們會獲得預期的值。

a = df[[ 'Total Traffic', 'UDP', 'NTP Amplification', 'triggers', 'ICMP']].head() 
for trig in pop_triggers: 
    a[trig] = a.triggers.apply(lambda x: 1 if trig in x else 0) 

我在這裏錯過了什麼?是不是因爲dask很懶惰,它不會按預期填充值?

編輯1: 我研究了一些地方的標誌是擺在首位(這被證明是遠遠低於我的預期,並得到了一些很奇怪的結果設置見下:

df2 = df[df['Total Traffic']==1] 
df2[['triggers']+pop_triggers].head() 

輸出:

 triggers Total Traffic UDP DNS 
9380 [ICMP, IP null, IP Private, TCP null, TCP SYN,... 1 1 1 
9388 [ICMP, IP null, IP Private, TCP null, TCP SYN,... 1 1 1 
19714 [ICMP, IP null, IP Private, UDP, NTP Amplifica... 1 1 1 
21556 [IP null] 1 1 1 
21557 [IP null] 1 1 1 

可能的錯誤也許

編輯2: 最小工作示例:

triggers = [['Total Traffic', 'DNS', 'UDP'],['TCP RST'],['Total Traffic'],['IP Private'],['ICMP']]*10 
df2 = dd.from_pandas(pd.DataFrame({'triggers':triggers}), npartitions=16) 
pop_triggers= ['Total Traffic', 'UDP', 'DNS', 'TCP SYN', 'TCP null', 'ICMP'] 
for trig in pop_triggers: 
    df2[trig] = df2.triggers.apply(lambda x: 1 if trig in x else 0) 
df2.head() 

輸出:

triggers Total Traffic UDP DNS TCP SYN TCP null ICMP 
0 [Total Traffic, DNS, UDP] 0 0 0 0 0 0 
1 [TCP RST] 0 0 0 0 0 0 
2 [Total Traffic] 0 0 0 0 0 0 
3 [IP Private] 0 0 0 0 0 0 

注:我更關心的事情DASK側,而不是熊貓

回答

2

在我的經驗applydask與明確metadata效果更好。有一些功能讓dask試圖猜測metadata,但我發現它很慢並且不總是可靠的。另外的指導是指定meta

我的經驗中的另一點是assigndf[col] = ...的效果更好。不知道這是一個錯誤,一個限制或在我身邊的濫用(我研究了一段時間,我不認爲這是一個錯誤)。

編輯:第一種模式是不行的,用於循環以前的專欄中trig值似乎與以後的值進行更新,因此在計算時間,這給所有列的最後一個值的唯一結果!

這不是一個錯誤,但不是一個錯誤,而是不計算立即計算結束的延遲計算的lambda結果,但尚未評估。見this discussion爲什麼它不起作用。

那麼我對你的模式將是:

cols = {} 
for trig in pop_triggers: 
    meta = (trig, int) 
    cols[trig] = df.triggers.apply(lambda x: 1 if trig in x else 0, meta=meta) 
df = df.assign(**cols) 

正確的方式:

(抱歉,以前也沒考,因爲我跑了相同的模式,除了我不不使用應用函數中的循環值,因此不會面對該行爲)

cols = {} 

for trig in pop_triggers: 
    meta = (trig, int) 

    def fn(x, t): 
     return 1 if t in x else 0 

    cols[trig] = ddf.triggers.apply(fn, args=(trig,), meta=meta) 
ddf = ddf.assign(**cols) 
+0

嗨亞歷克斯,恐怕這不起作用。嘗試檢查'df.head()'。 –

+0

所以我看到發生了什麼,從循環計算出來的最後一個serie被分配到所有列,看看可變性問題。這很奇怪,因爲我幾乎有完全相同的一段代碼,現在已經使用了幾個星期了......實際上,它感覺像'lambda'中的'trig'是可變的,所以計算時使用最後一個值所有列。 – Alex

+0

答案更新爲工作版本。與開發人員覈實這是否是預期的行爲(在這種情況下,我認爲文檔沒有強調該問題)或錯誤是值得的 – Alex