python - dask 和 pandas 数据帧中 apply 的不兼容性

标签 python pandas dask

我的 Dask 数据框 中的 triggers 列示例如下所示:

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。当我将其复制到 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

最佳答案

根据我的经验,dask 中的 apply 使用显式 metadata 效果更好。 。有一些功能可以让 dask 尝试猜测元数据,但我发现它很慢而且并不总是可靠。另外,指导是指定 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 数据帧中 apply 的不兼容性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46720983/

相关文章:

从另一个文件夹中的脚本调用时,Python 未在同一文件夹中找到模块

python - Pandas map 返回所有 NaN

python - 属性错误: 'DataFrame' object has no attribute 'compute'

python - 如何在dask debug中关闭python实例

python - 查找所有点对之间的欧氏距离

python - 创建子列表

c++ - C++ 中的简明列表/vector

csv - 如何从 CSV 文件读取 pandas 系列

python - 如何创建滑动窗口来合并不同的条目?

python - 同时运行两个 dask-ml 输入器而不是依次运行