我的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 TrafficDNS等列均包含值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

最佳答案

以我的经验,apply中的dask与显式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)

关于python - 在dask和pandas数据框中应用的不兼容性,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46720983/

10-12 16:50
查看更多