【问题标题】:Python: Each chunk of data consists of a variable amount of lines, how to determine the number of chunks total?Python:每个数据块由可变数量的行组成,如何确定总块数?
【发布时间】:2018-02-04 15:08:37
【问题描述】:

我有一个非常大的数据文件,每个条目看起来像这样:

    5 (this can be any number, call this line n)
Line 1
Line 2
Line 3
n lines, in this case 5, i.e. lines 4 - 8
Line 9
n lines, in this case again 5, i.e. lines 10-14
Line 15

基本上,每个条目都是以一行开头,然后是 3 行 + n 行 + 1 行 + n 行 + 1 行。

这个数字 n,是一个整数(但可能因条目而异)。有没有办法弄清楚我在这个文件中有多少数据条目?

我有一些代码,如果我知道有多少条目,那么我可以遍历每个条目...但是有没有办法首先计算出条目的数量?

谢谢!

编辑:以下是示例条目的两个示例 -

    5
10.0 0.0 0.0
0.0 10.0 0.0
0.0 0.0 10.0
A       -0.005364798      -0.022912843       0.017346957
B        0.527031905       0.603310150       0.560736787
B       -0.629466850      -0.628385741       0.628048126
B       -0.649090857       0.603667874      -0.726135880
B        0.683741908      -0.584386774      -0.700569743
    -17.862057
  -2.022841336      -1.477407454      -5.606136767
   2.521789668       2.889251770       2.572440406
  -0.401914888      -0.722582908       0.244151982
   0.806040926      -0.990697574       1.474733506
  -0.903074369       0.301436166       1.314862295
      0.016462

     7
 10.0 0.0 0.0
 0.0 10.0 0.0
 0.0 0.0 10.0
 A       -0.591644968      -0.645755982      -0.014245979
 B        1.198655655      -0.588872080      -0.025169784
 B       -1.460774580      -1.255848596       0.025804796
 B        0.321839745       2.199107994       0.050450166
 C        0.617684720      -1.389588077      -0.075897238
 C        0.493712792       1.349385956      -0.004249822
 D       -0.808145644       0.577304796       0.014326943
    -26.435922
   1.649465696      -2.945456091      -0.152209323
   0.531241391      -1.113956273      -0.135548573
  -0.529287352      -0.556746737      -0.061346528
  -2.152476371       6.326868481       0.441458459
  -1.633473432       3.325310912       0.291306019
   0.726490986      -8.268565793      -0.512575180
   1.408090505       3.232545501       0.128915126
      0.155658

第一个数字是一个整数(在这些示例中为 5 或 7),它决定了该条目之后的行数:

 10.0 0.0 0.0
 0.0 10.0 0.0
 0.0 0.0 10.0

以及紧随其后的行数,在第一种情况下是: -17.862057

每个条目看起来像这样。基本上,我们的目标是计算出总共有多少条目,利用第一个整数可以知道条目的其余部分跟随了多少行。

【问题讨论】:

  • “固定”行与“可变”行有什么区别吗?如果没有,在您用尽文件之前将无法确定n。使用一些巧妙的数据结构可能仍然可以优化。
  • 嗨,是的。固定行是各种浮点整数,而“变量”行是整数。已编辑我的帖子以明确这一点。
  • 您是否介意添加一个完整的示例输入文件(n 的一些小值和少量条目)以及您的代码应该做什么?这将有助于更好地了解您的要求。
  • 我添加了两个示例输入文件示例并解释了它的一般要点。这有意义吗?
  • 读取一个整数 n,然后使用 next 跳过 2 * n + 5 行,冲洗并重复。

标签: python database for-loop multiple-entries


【解决方案1】:

我已编写此代码来处理您给定的示例。它一开始不知道有多少条目,但它只是不断地从文件中读取,直到文件用完,以便提取每个条目。我已将您的示例输入保存在 input.txt 中。我现在还修改了代码以将数据作为浮点数读取。

import pprint
import functools

#helper function for reading multiple lines
def read_n(in_file, n):
    return [in_file.readline() for _ in range(n)]

#read one line of floats
def read_floats(line):
    return list(map(float, line.split()))

#reads several lines of floats
def float_lines(lines):
    return [read_floats(line) for line in lines]

def parse_entry(in_file):
    #get n
    n = in_file.readline().strip()

    if n:
        n = int(n)

        #read 3, n, 1, n, 1 lines
        head = float_lines(read_n(in_file, 3))
        head_data = [(line[0], read_floats(line[1:])) for line in map(str.strip, read_n(in_file, n))]
        mid = float(in_file.readline().strip())
        tail_data = float_lines(read_n(in_file, n))
        tail = float(in_file.readline().strip())

        #readline to eat the empty line between entries
        in_file.readline()

        return n, head, head_data, mid, tail_data, tail

with open("input.txt", "r") as input_file:
    #apply parse_entry until it stops returning
    entries = list(iter(functools.partial(parse_entry, input_file), None))

print(len(entries))
pprint.pprint(entries)

哪些输出:

2
[(5,
  [[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]],
  [('A', [-0.005364798, -0.022912843, 0.017346957]),
   ('B', [0.527031905, 0.60331015, 0.560736787]),
   ('B', [-0.62946685, -0.628385741, 0.628048126]),
   ('B', [-0.649090857, 0.603667874, -0.72613588]),
   ('B', [0.683741908, -0.584386774, -0.700569743])],
  -17.862057,
  [[-2.022841336, -1.477407454, -5.606136767],
   [2.521789668, 2.88925177, 2.572440406],
   [-0.401914888, -0.722582908, 0.244151982],
   [0.806040926, -0.990697574, 1.474733506],
   [-0.903074369, 0.301436166, 1.314862295]],
  0.016462),
 (7,
  [[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]],
  [('A', [-0.591644968, -0.645755982, -0.014245979]),
   ('B', [1.198655655, -0.58887208, -0.025169784]),
   ('B', [-1.46077458, -1.255848596, 0.025804796]),
   ('B', [0.321839745, 2.199107994, 0.050450166]),
   ('C', [0.61768472, -1.389588077, -0.075897238]),
   ('C', [0.493712792, 1.349385956, -0.004249822]),
   ('D', [-0.808145644, 0.577304796, 0.014326943])],
  -26.435922,
  [[1.649465696, -2.945456091, -0.152209323],
   [0.531241391, -1.113956273, -0.135548573],
   [-0.529287352, -0.556746737, -0.061346528],
   [-2.152476371, 6.326868481, 0.441458459],
   [-1.633473432, 3.325310912, 0.291306019],
   [0.726490986, -8.268565793, -0.51257518],
   [1.408090505, 3.232545501, 0.128915126]],
  0.155658)]

证明它找到了 2 个条目,并将它们解析为浮点数,然后输出条目。我不完全确定这些条目是什么,所以我将它们命名为模棱两可。请注意,我已经尽可能多地保留了我的大列表元组结构中的条目数据,因为我也不确定哪些位是相关的,所以原始文件应该几乎可以从内存中的条目中重建。

关于以字符开头的行 - 首先将str.strip 应用于该行,因为有时字符前有一个空格。然后它将line 分成line[0]line[1:](这是字符)和代表数据的字符串切片,然后照常操作。

更多关于我如何将字符与浮点数分开:

采取以下行:

 A       -0.005364798      -0.022912843       0.017346957

这将被解析:

head_data = [(line[0], read_floats(line[1:])) for line in map(str.strip, read_n(in_file, n))]

但是,如果我们只考虑这一行,我们可以少看表达式。发生在这条线上的第一件事是str.strip,来自map(str.strip..)。这会去除任何尾随和前导空格,以确保第一个字符是要删除的字母。这意味着该行在内存中的状态现在是:

"A       -0.005364798      -0.022912843       0.017346957"

然后该行被分成line[0]read_floats(line[1:])。这是区分字符串和浮点数的地方 - 字符串与字符串的其余部分分开,然后传递给read_floats。这是使用切片表示法,这是 Python 用于获取可迭代的子列表的强大语法。切片 1: 表示“从索引 1 到字符串末尾的切片”。为清楚起见:

line[0] == "A"
line[1:] == "      -0.005364798      -0.022912843       0.017346957"

for _ 是一种 Python 约定,当您只需要重复某事时,无需跟踪它是哪次重复。即它为range(n) 中的每个数字读取一行,因此它读取n 行,但它不需要跟踪当前行是哪个数字。它也可以写成for i in range(n),除了i 不会被使用,所以迭代器被称为_ 来表明你不想要它。

if n: 检查字符串 n 是否不为空。这是因为当您readline() 一个文件已用尽时,会返回一个空字符串。这意味着程序在处理完文件时不会崩溃,而是会巧妙地停止解析条目。这很重要,因为我们不知道条目的数量,所以我们一直尝试读取 n,直到我们无法再读取 n,所以我们必须使用 if 语句。

关于为什么条目看起来如此复杂 - parse_entry(input_file) 只会解析一个条目。解析所有条目需要所有其他行李。 functools.partial(parse_entry, input_file) 表示“将参数input_file 应用于函数parse_entry”。然后使用iter 继续执行此操作,直到它返回None。这是一个非常有用的技巧 - iter 函数可以被赋予任何函数,然后是一个要停止的值,它会不断从函数返回值,直到它达到“停止”值。一个更简单、更常见的例子可能是iter(sys.stdin.readline, "a\n")。这将继续读取来自stdin 的行,直到遇到仅包含a 的行。

关于元组和元组解包 - 你可以这样做:

for n, head, head_data, mid, tail_data, tail in entries:
    print("n is {}".format(n))
    print("the first item of head_data is {}".format(head_data[0]))

    for i in tail_data:
        print("tail data item: {}".format(i))

这导致输出:

n is 5
the first item of head_data is ('A', [-0.005364798, -0.022912843, 0.017346957])
tail data item: [-2.022841336, -1.477407454, -5.606136767]
tail data item: [2.521789668, 2.88925177, 2.572440406]
tail data item: [-0.401914888, -0.722582908, 0.244151982]
tail data item: [0.806040926, -0.990697574, 1.474733506]
tail data item: [-0.903074369, 0.301436166, 1.314862295]
n is 7
the first item of head_data is ('A', [-0.591644968, -0.645755982, -0.014245979])
tail data item: [1.649465696, -2.945456091, -0.152209323]
tail data item: [0.531241391, -1.113956273, -0.135548573]
tail data item: [-0.529287352, -0.556746737, -0.061346528]
tail data item: [-2.152476371, 6.326868481, 0.441458459]
tail data item: [-1.633473432, 3.325310912, 0.291306019]
tail data item: [0.726490986, -8.268565793, -0.51257518]
tail data item: [1.408090505, 3.232545501, 0.128915126]

希望这能证明您可以如何使用该结构。

【讨论】:

  • 嘿,非常感谢您参与其中!当我尝试在我的大数据集条目 (input.txt) 上运行它时,我收到此错误:ValueError: invalid literal for int() with base 10: '10.0 0.0 0.0' 这与我在我用我自己的代码试过这个。似乎 int() 正在检查第二行而不是第一行?将下一行保留为字符串似乎应该没问题,重要的是确保第一行被读取为整数。
  • 好的,我几乎睡觉了。我怀疑这是因为您的数据集要么在条目之间没有空行,要么不一致。如果没有它们,您可以删除空行食器。如果它有时有它们,我真的必须在早上这样做。
  • 哦,你知道我想我想出了那部分,谢谢你的帮助!我想知道你是否能像你说的那样帮忙做最后一件事,那就是阅读一排花车。如果我想在某些行中读取为浮点数(即 10.0 0.0 0.0),但我也想在诸如“A -0.005364798 -0.022912843 0.017346957”之类的行中读取,这将是一个字符后跟浮点数,你最了解 python练习这样做的方法?
  • 现在修改代码以使用浮点数。让我知道是否应该改变它,我会在下班后这样做。请注意,由于我不清楚问题出在哪里,所以我已经使用我的 line-eater 离开了它。
  • 非常感谢!对于“head_data”部分,您用来指定第一个值是字符串而其余的是浮点数的具体命令是什么?我看到你做了 line[0] 来调用第一个条目,当你做了“for line in map(str.strip, read_n(in_file, n))”时,你是如何只将第一个条目映射到字符串的? (我也接受了你的回答,但只是从学习的角度问这个)
猜你喜欢
  • 2011-05-22
  • 1970-01-01
  • 2015-09-16
  • 2017-07-02
  • 1970-01-01
  • 1970-01-01
  • 2014-11-16
  • 2022-11-25
  • 1970-01-01
相关资源
最近更新 更多