【问题标题】:easy save/load of data in python在 python 中轻松保存/加载数据
【发布时间】:2010-12-15 13:02:10
【问题描述】:

在 python 中保存和加载数据的最简单方法是什么,最好是人类可读的输出格式?

我保存/加载的数据由两个浮点向量组成。理想情况下,这些向量将在文件中命名(例如 X 和 Y)。

我当前的save()load() 函数使用file.readline()file.write() 和字符串到浮点数的转换。一定有更好的东西。

【问题讨论】:

    标签: python io


    【解决方案1】:

    获得人类可读输出的最简单方法是使用 JSON 等序列化格式。 Python 包含一个json 库,可用于将数据序列化到字符串和从字符串中提取数据。与pickle 一样,您可以将其与 IO 对象一起使用以将其写入文件。

    import json
    
    file = open('/usr/data/application/json-dump.json', 'w+')
    data = { "x": 12153535.232321, "y": 35234531.232322 }
    
    json.dump(data, file)
    

    如果你想取回一个简单的字符串而不是将其转储到文件中,你可以使用 json.dumps() 代替:

    import json
    print json.dumps({ "x": 12153535.232321, "y": 35234531.232322 })
    

    从文件中读回同样简单:

    import json
    
    file = open('/usr/data/application/json-dump.json', 'r')
    print json.load(file)
    

    json 库功能齐全,所以我推荐checking out the documentation 看看你可以用它做什么。

    【讨论】:

      【解决方案2】:

      有几种选择——我不完全知道你喜欢什么。如果两个向量的长度相同,您可以使用numpy.savetxt() 将向量保存为列,例如xy

       # saving:
       f = open("data", "w")
       f.write("# x y\n")        # column names
       numpy.savetxt(f, numpy.array([x, y]).T)
       # loading:
       x, y = numpy.loadtxt("data", unpack=True)
      

      如果您要处理较大的浮点向量,则无论如何都应该使用 NumPy。

      【讨论】:

      • 在我看来 numpy.savetxt 将字符串作为其第一个参数。
      • @nos:它接受文件名或文件对象。可能是旧版本的 NumPy 只接受一个字符串。我传递了一个文件对象,以便能够在之前写入标题行。
      • 如果我使用 f = open("data", "w+") 会保存
      • 您可以直接添加标题行in numpy.savetxt,这要归功于可选参数,如numpy.savetxt("data", numpy.array([x, y]).T, header="x y")(注释符号和换行符会自动添加到标题行)。多亏了这一点,您不再需要进行任何额外的文件处理,而且一切都在一行中。
      • @Dalker 是的,这些天代码可以简化,但是savetxt() didn't have this option at the time
      【解决方案3】:
      • 如果它应该是人类可读的,我会 也可以使用 JSON。除非你需要 与企业型交换 人们,他们更喜欢 XML。 :-)

      • 如果它应该是人类可编辑和 不太复杂,我可能会去 使用某种类似 INI 的格式, 比如configparser。

      • 如果比较复杂,不需要 被交换,我会去 腌制数据,除非它非常 复杂,在这种情况下我会使用 ZODB。

      • 如果数据量很大,并且需要 要交换,我会使用 SQL。

      我认为这几乎涵盖了它。

      【讨论】:

      • CSV 是否符合这些要求?
      • 如果您的数据非常简单(即表格),并且您希望能够将其导入电子表格,那么CSV 是一种很好的格式。否则它太未定义,不容易阅读或编辑,无法处理复杂的数据,如果数据集很大,会很痛苦。
      【解决方案4】:

      一个简单的序列化格式是JSON

      您可以使用json Python 模块。

      【讨论】:

        【解决方案5】:

        这是一个编码器示例,直到您可能想为Body 类编写代码:

        # add this to your code
        class BodyEncoder(json.JSONEncoder):
            def default(self, obj):
                if isinstance(obj, np.ndarray):
                    return obj.tolist()
                if hasattr(obj, '__jsonencode__'):
                    return obj.__jsonencode__()
                if isinstance(obj, set):
                    return list(obj)
                return obj.__dict__
        
            # Here you construct your way to dump your data for each instance
            # you need to customize this function
            def deserialize(data):
                bodies = [Body(d["name"],d["mass"],np.array(d["p"]),np.array(d["v"])) for d in data["bodies"]]
                axis_range = data["axis_range"]
                timescale = data["timescale"]
                return bodies, axis_range, timescale
        
            # Here you construct your way to load your data for each instance
            # you need to customize this function
            def serialize(data):
                file = open(FILE_NAME, 'w+')
                json.dump(data, file, cls=BodyEncoder, indent=4)
                print("Dumping Parameters of the Latest Run")
                print(json.dumps(data, cls=BodyEncoder, indent=4))
        

        这是我要序列化的类的示例:

        class Body(object):
            # you do not need to change your class structure
            def __init__(self, name, mass, p, v=(0.0, 0.0, 0.0)):
                # init variables like normal
                self.name = name
                self.mass = mass
                self.p = p
                self.v = v
                self.f = np.array([0.0, 0.0, 0.0])
        
            def attraction(self, other):
                # not important functions that I wrote...
        

        这是序列化的方法:

        # you need to customize this function
        def serialize_everything():
            bodies, axis_range, timescale = generate_data_to_serialize()
        
            data = {"bodies": bodies, "axis_range": axis_range, "timescale": timescale}
            BodyEncoder.serialize(data)
        

        这里是如何转储:

        def dump_everything():
            data = json.loads(open(FILE_NAME, "r").read())
            return BodyEncoder.deserialize(data)
        

        【讨论】:

          【解决方案6】:

          由于我们谈论的是人类编辑文件,我假设我们谈论的是相对较少的数据。

          下面的骨架实现怎么样。它只是将数据保存为 key=value 对,并适用于列表、元组和许多其他内容。

              def save(fname, **kwargs):
                f = open(fname, "wt")
                for k, v in kwargs.items():
                  print >>f, "%s=%s" % (k, repr(v))
                f.close()
          
              def load(fname):
                ret = {}
                for line in open(fname, "rt"):
                  k, v = line.strip().split("=", 1)
                  ret[k] = eval(v)
                return ret
          
              x = [1, 2, 3]
              y = [2.0, 1e15, -10.3]
              save("data.txt", x=x, y=y)
              d = load("data.txt")
              print d["x"]
              print d["y"]
          

          【讨论】:

          • 我不喜欢 eval 的东西,它允许用户执行任意代码会带来奇怪的东西
          • 假设它是简单的东西,ast.literal_eval 可以解决这个问题。不过,我更喜欢 json 方法。
          【解决方案7】:

          正如我在接受的答案中评论的那样,使用numpy 这可以通过一个简单的单线来完成:

          假设您将numpy 导入为np(这是常见做法),

          np.savetxt('xy.txt', np.array([x, y]).T, fmt="%.3f", header="x   y")
          

          将以(可选)格式保存数据并

          x, y = np.loadtxt('xy.txt', unpack=True)
          

          将加载它。

          文件xy.txt 将如下所示:

          # x   y
          1.000 1.000
          1.500 2.250
          2.000 4.000
          2.500 6.250
          3.000 9.000
          

          请注意,格式字符串fmt=... 是可选的,但如果目标是人类可读性,它可能会非常有用。如果使用,则使用通常的类似printf 的代码指定(在我的示例中:带有 3 位小数的浮点数)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-09-11
            • 2012-02-05
            • 1970-01-01
            • 1970-01-01
            • 2014-10-02
            相关资源
            最近更新 更多