合并Dask数据框时遇到问题

时间:2019-06-02 08:43:46

标签: python pandas dask

我有几个.pcap文件,我要将其数据写入一个大型dask数据帧。当前,使用第一个文件中的数据初始化dask数据帧。然后应该处理其余的pcap文件,并使用merge / concat将其添加到dask数据帧中。但是,当我检查合并的dask数据帧的行数时,它不会增加。怎么了?

我也不确定我是否针对自己的用例使用正确的方法。我试图将我的整个数据集转换成一个巨大的dask数据框,并将其写到h5文件中。我的计算机没有足够的内存来加载整个数据集,所以这就是我使用dask的原因。这个想法是加载包含整个数据集的dask数据框,以便我可以对整个数据集进行操作。我是个新手,我已经阅读了一些文档,但是我对模糊人如何处理从磁盘而不是从内存中加载数据的方式仍然感到困惑。我对分区如何快速工作也很模糊。具体来说,我也不确定chunksize与分区有何不同,因此无法正确分区此数据帧。任何提示和建议都会有所帮助。

如前所述,我已经阅读了文档的主要部分。

我已经尝试使用dd.merge(dask_df,panda_df),如文档所示。当我初始化dask数据框时,它以6行开始。当我使用合并时,行数减少到1

我也尝试过使用concat。同样,初始化期间我有6行计数。但是,在concat操作之后,行数仍保持为6。我希望行数会增加。

这是初始化函数

import os
import sys
import h5py
import pandas as pd
import dask.dataframe as dd
import gc
import pprint
from scapy.all import *
flags = {
        'R': 0,
        'A': 1,
        'S': 2,
        'DF':3,
        'FA':4,
        'SA':5,
        'RA':6,
        'PA':7,
        'FPA':8
    }

def initialize(file):
    global flags
    data = {
        'time_delta': [0],
        'ttl':[],
        'len':[],
        'dataofs':[],
        'window':[],
        'seq_delta':[0],
        'ack_delta':[0],
        'flags':[]
    }
    scap = sniff(offline=file,filter='tcp and ip')
    for packet in range(0,len(scap)):
        pkt = scap[packet]
        flag = flags[str(pkt['TCP'].flags)]
        data['ttl'].append(pkt['IP'].ttl)
        data['len'].append(pkt['IP'].len)
        data['dataofs'].append(pkt['TCP'].dataofs)
        data['window'].append(pkt['TCP'].window)
        data['flags'].append(flag)
        if packet != 0:
            lst_pkt = scap[packet-1]
            data['time_delta'].append(pkt.time - lst_pkt.time)
            data['seq_delta'].append(pkt['TCP'].seq - lst_pkt['TCP'].seq)
            data['ack_delta'].append(pkt['TCP'].ack - lst_pkt['TCP'].ack)

    panda = pd.DataFrame(data=data)
    panda['ttl']=panda['ttl'].astype('float16')
    panda['flags']=panda['flags'].astype('float16')
    panda['dataofs']=panda['dataofs'].astype('float16')
    panda['len']=panda['len'].astype('float16')
    panda['window']=panda['window'].astype('float32')
    panda['seq_delta']=panda['seq_delta'].astype('float32')
    panda['ack_delta']=panda['ack_delta'].astype('float32')

    df =dd.from_pandas(panda,npartitions=6)

    gc.collect()
    return df

这是串联函数

def process(file):
    global flags
    global df
    data = {
        'time_delta': [0],
        'ttl':[],
        'len':[],
        'dataofs':[],
        'window':[],
        'seq_delta':[0],
        'ack_delta':[0],
        'flags':[]
    }
    scap = sniff(offline=file,filter='tcp and ip')
    for packet in range(0,len(scap)):
        pkt = scap[packet]
        flag = flags[str(pkt['TCP'].flags)]
        data['ttl'].append(pkt['IP'].ttl)
        data['len'].append(pkt['IP'].len)
        data['dataofs'].append(pkt['TCP'].dataofs)
        data['window'].append(pkt['TCP'].window)
        data['flags'].append(flag)
        if packet != 0:
            lst_pkt = scap[packet-1]
            data['time_delta'].append(pkt.time - lst_pkt.time)
            data['seq_delta'].append(pkt['TCP'].seq - lst_pkt['TCP'].seq)
            data['ack_delta'].append(pkt['TCP'].ack - lst_pkt['TCP'].ack)

    panda = pd.DataFrame(data=data)
    panda['ttl']=panda['ttl'].astype('float16')
    panda['flags']=panda['flags'].astype('float16')
    panda['dataofs']=panda['dataofs'].astype('float16')
    panda['len']=panda['len'].astype('float16')
    panda['window']=panda['window'].astype('float32')
    panda['seq_delta']=panda['seq_delta'].astype('float32')
    panda['ack_delta']=panda['ack_delta'].astype('float32')

    #merge version dd.merge(df, panda)
    dd.concat([df,dd.from_pandas(panda,npartitions=6)])

    gc.collect()

这是主程序

directory = 'dev/streams/'
files = os.listdir(directory)
df = initialize(directory+files[0])
files.remove(files[0])
for file in files:
    process(directory+file)
print(len(df))

使用合并:

print(len(df)) = 1

使用concat:

print(len(df))=6

预期:

print(len(df)) > 10,000

1 个答案:

答案 0 :(得分:1)

尝试根据您的连击操作显式返回df

df = dd.concat([df, dd.from_pandas(panda,npartitions=6)])

也不要复制完全相同的代码块,而是将它们封装在另一个函数中:

def process_panda(file_wpath, flags):
    data = {
    [...]
    panda['ack_delta']=panda['ack_delta'].astype('float32')
    return panda

然后,您只需要测试要处理的文件是否是第一个文件,因此您的主要代码将变为:

import os
import sys
import h5py
import pandas as pd
import dask.dataframe as dd
import gc
import pprint
from scapy.all import *

flags = {
        'R': 0,
        'A': 1,
        'S': 2,
        'DF':3,
        'FA':4,
        'SA':5,
        'RA':6,
        'PA':7,
        'FPA':8
    }

directory = 'dev/streams/'
files = os.listdir(directory)

for file in files:
    file_wpath = os.path.join(directory, file)
    panda = process_panda(file_wpath, flags)
    if file == files[0]:
        df = dd.from_pandas(panda, npartitions=6)
    else:
        df = dd.concat([df, dd.from_pandas(panda, npartitions=6)])        
    gc.collect()

print(len(df))