使用Python从数据文件中提取几行
我有一个很大的文件,里面有很多数据。我需要每5000行左右提取3行。这个数据文件的格式如下:
...
O_sh 9215 1.000000 -2.304400
-1.0680E+00 1.3617E+00 -5.7138E+00
O_sh 9216 1.000000 -2.304400
-8.1186E-01 -1.7454E+00 -5.8169E+00
timestep 501 9216 0 3 0.000500
20.54 -11.85 35.64
0.6224E-02 23.71 35.64
-20.54 -11.86 35.64
Li 1 6.941000 0.843200
3.7609E-02 1.1179E-01 4.1032E+00
Li 2 6.941000 0.843200
6.6451E-02 -1.3648E-01 1.0918E+01
...
我需要的是每次以“timestep”开头的那一行之后的三行,所以在这个例子中,我需要的是3x3的数组:
20.54 -11.85 35.64
0.6224E-02 23.71 35.64
-20.54 -11.86 35.64
每次“timestep”出现时,都要把这些数据写入一个输出文件。
然后,我还需要把所有这些数组的平均值放在一个数组里。也就是说,得到一个数组,这个数组的每个元素都是在所有数组中同一位置的元素的平均值,涵盖整个文件。
我已经在这个问题上努力了一段时间,但还没有成功提取到正确的数据。
非常感谢,这不是作业。你们的建议将有助于科学的进步!=)
谢谢,
5 个回答
1
好的,你可以这样做:
算法:
Read the file line by line
if the line starts with "timestep":
read the next three lines
take the average as needed
代码:
def getArrays(f):
answer = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
count = 0
line = f.readline()
while line:
if line.strip().startswith("timestep"):
one, two, three = getFloats(f.readline().strip()), getFloats(f.readline().strip()), getFloats(f.readline().strip())
answer[0][0] = ((answer[0][0]*count) + one[0])/(count+1)
answer[0][1] = ((answer[0][0]*count) + one[1])/(count+1)
answer[0][2] = ((answer[0][0]*count) + one[2])/(count+1)
answer[1][0] = ((answer[0][0]*count) + two[0])/(count+1)
answer[1][1] = ((answer[0][0]*count) + two[1])/(count+1)
answer[1][2] = ((answer[0][0]*count) + two[2])/(count+1)
answer[2][0] = ((answer[0][0]*count) + three[0])/(count+1)
answer[2][1] = ((answer[0][0]*count) + three[1])/(count+1)
answer[2][2] = ((answer[0][0]*count) + three[2])/(count+1)
line = f.readline()
count += 1
return answer
def getFloats(line):
answer = []
for num in line.split():
if "E" in num:
parts = num.split("E")
base = float(parts[0])
exp = int(parts[1])
answer.append(base**exp)
else:
answer.append(float(num))
return answer
现在,answer
是一个包含所有 3x3 数组的列表。我不知道你想怎么计算平均值,所以如果你把这个告诉我,我可以把它加到这个算法里。否则,你可以写一个函数来处理我的数组,计算出需要的平均值。
希望这对你有帮助。
3
假设这不是作业,我觉得用正则表达式来解决这个问题有点过于复杂了。如果你知道在以'timestep'开头的那一行之后需要三行内容,为什么不这样处理呢:
Matrices = []
with open('data.txt') as fh:
for line in fh:
# If we see timestep put the next three lines in our Matrices list.
if line.startswith('timestep'):
Matrices.append([next(fh) for _ in range(3)])
根据评论的内容,当你想从文件中提取接下来的三行时,可以使用next(fh)来保持文件句柄的同步。谢谢!
2
我建议你使用一个协程(如果你不太了解的话,可以把它看作是一个可以接收值的生成器),这样在遍历文件的时候就能保持一个运行中的平均值。
def running_avg():
count, sum = 0, 0
value = yield None
while True:
if value:
sum += value
count += 1
value = yield(sum/count)
# array for keeping running average
array = [[running_avg() for y in range(3)] for x in range(3)]
# advance to first yield before we begin
[[elem.next() for elem in row] for row in array]
with open('data.txt') as f:
idx = None
for line in f:
if idx is not None and idx < 3:
for i, elem in enumerate(line.strip().split()):
array[idx][i].send(float(elem))
idx += 1
if line.startswith('timestep'):
idx = 0
要把array
转换成一个平均值的列表,只需要调用每个协程的next
方法,它会返回当前的平均值:
averages = [[elem.next() for elem in row] for row in array]
这样你就会得到类似这样的结果:
averages = [[20.54, -11.85, 35.64], [0.006224, 23.71, 35.64], [-20.54, -11.86, 35.64]]