我有一个包含大量数据(3 GB)的文本文件。此文本文件的每一行包含时间,源IP,目标IP和大小。如您所知,IP地址最后一节中的数字显示端口地址。我想把这些端口地址带到一个直方图中,我为它做了10 000行数据,但我猜想Python代码不能为大量数据执行。我简要解释一下我写的代码。首先,我读取了10 000个数据点,之后我将它们拆分并将所有内容放入名为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()
这是行格式:
15:42:42.719063 IP 129.241.138.133.47843 > 129.63.27.12.2674: tcp 1460
15:42:42.719205 IP 129.241.138.133.47843 > 129.63.27.12.2674: tcp 1460
15:42:42.719209 IP 129.63.57.175.45241 > 62.85.5.142.55455: tcp 0
15:42:42.719213 IP 24.34.41.8.1236 > 129.63.1.23.443: tcp 394
15:42:42.719217 IP 59.167.148.152.25918 > 129.63.57.40.36075: tcp 0
15:42:42.719260 IP 129.63.223.16.2823 > 80.67.87.25.80: tcp 682
15:42:42.719264 IP 129.63.184.118.2300 > 64.111.215.46.80: tcp 0
15:42:42.719269 IP 129.63.184.118.2300 > 64.111.215.46.80: tcp 0
答案 0 :(得分:3)
我不知道数据是什么样的,但我认为问题在于你试图将其全部保存在内存中。你需要一点一点地做read the lines one by one,并在你去的时候建立直方图。
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
,因为您已经拥有histogram
字典中的频率。
答案 1 :(得分:3)
您可以使用正则表达式并在外部循环编译它。
完全以懒惰模式逐行阅读文件。
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()
此代码考虑到这样一个事实,即您只需要(n-6) / 7
个第一项,n
是源文件的行数。如果某些+1/-1
不完全准确,请尝试使用import re
import matplotlib.pyplot as plt
import pylab
r = re.compile(r'(?<=\.)[0-9]{2,5}(?= \>)')
ports = [ re.search(r, line).group(0) for line in open("test.data", "r") ]
ports = ports[0:(len(ports) - 6) // 7]
numBins = 20
plt.hist(ports, numBins, color='red', alpha=0.8)
plt.show()
。在最后删除不需要的项目可以让你的循环不会被检查每次迭代的条件。
修改强>
您可以结合以上几点来获得更简洁有效的代码:
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
修改强>
如果您认为您的端口列表太大而无法放入RAM(我觉得不太可能),我的建议是使用端口字典:
>>> ports
{
"8394": 182938,
"8192": 839288,
"1283": 9839
}
这会给你类似的东西:
plt.hist
请注意,在这种情况下,您必须修改对{{1}}的调用。
答案 2 :(得分:1)
您可以使用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})
也可能值得查看不同的绘图方式,matplotlib不是最有效的:
答案 3 :(得分:0)
听起来你应该逐行迭代并使用正则表达式来查找端口。尝试这样的事情:
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
答案 4 :(得分:0)
我知道这不是对你的问题的立即回应,但作为python的新手,有一个很好的Coursera课程处理这个主题。 “为每个人编程(Python)”它是免费的,不会占用你太多的时间。课程将于2015年2月2日开始。教科书“信息学的Python:探索信息”也是免费的知识共享下载。在http://www.pythonlearn.com/book.php我希望这有帮助。