Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Python中处理大量数据_Python_Text Files_Histogram_Large Data - Fatal编程技术网

如何在Python中处理大量数据

如何在Python中处理大量数据,python,text-files,histogram,large-data,Python,Text Files,Histogram,Large Data,我有一个包含大量数据(3 GB)的文本文件。此文本文件的每一行都包含时间、源IP、目标IP和大小。正如您所知,IP地址最后一部分中的数字显示端口地址。我想把这些端口地址放到一个直方图中,我这样做是为了10000行数据,但是我可以猜Python代码不能为这么大的数据量执行。我简要解释了我编写的代码。首先,我读取10000个数据点,然后将它们拆分,并将所有数据点放入名为everything_list的列表中。忽略while循环工作的条件。后来我把所有的端口地址放在一个列表中,并画出它们的柱状图。 现

我有一个包含大量数据(3 GB)的文本文件。此文本文件的每一行都包含时间、源IP、目标IP和大小。正如您所知,IP地址最后一部分中的数字显示端口地址。我想把这些端口地址放到一个直方图中,我这样做是为了10000行数据,但是我可以猜Python代码不能为这么大的数据量执行。我简要解释了我编写的代码。首先,我读取10000个数据点,然后将它们拆分,并将所有数据点放入名为everything_list的列表中。忽略while循环工作的条件。后来我把所有的端口地址放在一个列表中,并画出它们的柱状图。 现在假设我有一百万行数据,我一开始无法读取它们,更不用说对它们进行分类了。有些人告诉我使用数组,有些人告诉我处理一块数据,然后再处理另一块数据。我对所有人说的话感到困惑。有人能帮我解决这个问题吗

text_file = open("test.data", "r")
a = text_file.read()
text_file.close()

everything_list = a.split()
source_port_list = []
i=0
while 6+7*i<len(everything_list):

    source_element = everything_list[2+7*i]
    source_port_position = source_element.rfind('.')
    source_port_number = int(source_element[source_port_position + 1:])
    source_port_list.append(source_port_number)

    i=i+1


import matplotlib.pyplot as plt
import pylab


numBins = 20
plt.hist(source_port_list, numBins, color='red', alpha=0.8)
plt.show()

我不知道这些数据是什么样子的,但我认为问题在于你试图一次将它们全部保存在内存中。你需要一点一点地做,并在你做的时候建立柱状图

histogram = {}
with open(...) as f:
    for line in f:
        ip = ...
        if ip in histogram:
            histogram[ip] += 1
        else:
            histogram[ip] = 1

您现在可以绘制直方图,但是使用
plt.plot
而不是
plt.hist
,因为您已经在
直方图
字典中找到了频率。

听起来您应该逐行迭代并使用regex来查找端口。试着这样做:

import re

ports = []
with open("path/to/your/text/file.txt", 'r') as infile:
    for line in infile:
        ports.append(re.findall(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\.(\d+)", line))
        # that regex explained:
        # # re.compile(r"""
        # #     \d{1,3}\.       # 1-3 digits followed by a literal .
        # #     \d{1,3}\.       # 1-3 digits followed by a literal .
        # #     \d{1,3}\.       # 1-3 digits followed by a literal .
        # #     \d{1,3}\.       # 1-3 digits followed by a literal .
        # #     (               # BEGIN CAPTURING GROUP
        # #       \d+           #   1 or more digits
        # #     )               # END CAPTURING GROUP""", re.X)
这是假设您的IP/端口的格式与您在注释中解释的相同

IP.IP.IP.IP.PORT

您可以使用正则表达式并在循环外部编译它

惰性模式下逐行读取文件

import re
import matplotlib.pyplot as plt
import pylab

r = re.compile(r'(?<=\.)[0-9]{2,5}(?= \>)')
ports = []

for line in open("test.data", "r"):
    ports.append(re.search(r, line).group(0))

# determines the number of lines you want to take into account
i = (len(ports) - 6) // 7

# keeps only the first i elements
ports = ports[0:i]

numBins = 20
plt.hist(ports, numBins, color='red', alpha=0.8)
plt.show()
编辑:

如果您认为您的端口列表太大,无法放入RAM(我发现这不太可能),我的建议是使用端口目录:

ports = {}
for line in open("test.data", "r"):
    port = re.search(r, line).group(0)
    if not ports.get(port, False):
        ports[port] = 0
    ports[port] += 1
这会给你一些类似的东西:

>>> ports
{
    "8394": 182938,
    "8192": 839288,
    "1283": 9839
}

请注意,在这种情况下,必须修改对
plt.hist
的调用。

您可以使用split和defaultdict,这将更有效:

from collections import defaultdict

d = defaultdict(int)
with open("a_file.txt") as f:
    for line in f:
         d[line.split()[2].rsplit(".",1)[-1]] += 1 
print(d)

defaultdict(<type 'int'>, {'1236': 1, '2300': 1, '47843': 2, '45241': 1, '25918': 1, '2823': 1})
从集合导入defaultdict
d=默认dict(int)
打开(“a_file.txt”)作为f:
对于f中的行:
d[line.split()[2].rsplit(“.”,1)[-1]+=1
印刷品(d)
defaultdict(,{'1236':1,'2300':1,'47843':2,'45241':1,'25918':1,'2823':1})
也许还值得检查不同的绘图方式,matplotlib并不是最有效的:

from collections import defaultdict

d = defaultdict(int)
with open("a_file.txt") as f:
    for line in f:
         d[line.split()[2].rsplit(".",1)[-1]] += 1 
print(d)

defaultdict(<type 'int'>, {'1236': 1, '2300': 1, '47843': 2, '45241': 1, '25918': 1, '2823': 1})


我知道这不是对你问题的直接回答,但作为python新手,有一个很好的课程来处理这个问题。“为每个人编程(Python)”这是免费的,不会占用你太多的时间。课程于2015年2月2日开始。另外,《Python for Informatics:Exploring Information》(Python for Informatics:Exploring Information)是一本免费的Creative Commons下载。至少,我希望这会有所帮助。

您有多少ram将决定您可以在内存中存储多少,而且实际ip中的最后数字与端口无关。您可以转储源文件的一些行吗,为了得到准确的结构?@PadraicCchanningham我想他的意思是
127.0.0.1:8080
例如,任何将整个文件读入内存的方法都是错误的,迭代文件对象并逐行解析,这将立即节省一些gig。我想如果你只是循环文件对象,你的很多问题都会消失。如果你能像你的问题一样添加一个文件片段,很难在你的评论中看到实际的格式,那么defaultdict会更有趣。还有一本反字典。对我来说,有时候简单胜过性能。你介意重写整个代码吗?由于我是一个新的python用户,我不知道如何进行这些更改!哎呀,最后一行错了,现在修好了。它所做的是在这些行中进行迭代,计算它看到给定ip的次数。直方图字典具有IP键和相应计数的值。最后一行只是将ip的计数从1开始,if语句的另一个分支将增加它在该行上找到的ip的计数。其他答案中描述了如何从线路获取ip。我将其保留为
ip=…
供您填写,不介意前两条注释。它们只是可能的性能改进,使用其他数据结构的结果
,port=line.rsplit(“.”,1)
会更好,我不认为这是真正的问题though@PadraicCunningham当然问题是
a=text\u file.read()
,但我更喜欢在这样的情况下使用正则表达式:一点也不,因为每行中有两个端口,OP的代码只能找到其中一个。您介意重写整个代码吗?由于我是一个新的python用户,我不知道如何进行这些更改!顺便说一句,我不知道你代码的最后一行是做什么的@克里斯托弗·保罗一世使用正则表达式的扩展定义进行编辑。它基本上会在日志中找到任何看起来像IP地址的内容(1-3位四次,用点分隔),然后将端口号分隔并保存在列表中。我实际上无法重写您的代码,因为我对matplotlib一无所知,所以我不知道它在做什么,而不是它能做得更好!:)但问题是,我将有一个长长的端口列表,我可能没有足够的RAM容量来存储所有端口。@CristopherVanPaul,您可能需要大量的数据来使用所有24 Gig的数据ram@CristopherVanPaul您可以将它们放在字典中,其中键是端口号,值是找到的端口数-这将节省大量空间potentially@Jivan,据我所知,如果我想这样做,我不应该用hist来做,因为hist会获取所有数据,然后再进行绘图。我应该处理一个数据块,然后处理另一个数据块,然后…:@Jivan,
my_list[n:://code>实际上从n返回到最后,而不是现在<
from collections import defaultdict

d = defaultdict(int)
with open("a_file.txt") as f:
    for line in f:
         d[line.split()[2].rsplit(".",1)[-1]] += 1 
print(d)

defaultdict(<type 'int'>, {'1236': 1, '2300': 1, '47843': 2, '45241': 1, '25918': 1, '2823': 1})