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