我的 Dask数据框中triggers
列的示例如下所示:
0 [Total Traffic, DNS, UDP]
1 [TCP RST]
2 [Total Traffic]
3 [IP Private]
4 [ICMP]
Name: triggers, dtype: object
我希望通过执行以下操作,创建上述数组的一个热编码版本(例如,将1
放在第1行的DNS
列中)。 pop_triggers
包含triggers
的所有可能值。
for trig in pop_triggers:
df[trig] = df.triggers.apply(lambda x: 1 if trig in x else 0)
但是,Total Traffic
,DNS
等列都包含值0,而不是相关值的1。当我将它复制到pandas数据帧并执行相同的操作时,它们会得到预期的值。
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方面而不是Pandas
答案 0 :(得分:2)
根据我的经验apply
dask
使用明确的metadata
效果更好。有一些功能让dask
尝试猜测metadata
,但我发现它很慢并且不总是可靠的。指南也是指定meta
。
根据我的经验,另一点是assign
比df[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)