【问题标题】:How to Read csv file upto a certain row and store in a variable如何将csv文件读取到某一行并存储在变量中
【发布时间】:2019-04-21 10:52:32
【问题描述】:

我想读入一个 csv 文件,然后将数据作为特定变量存储在标题下。

我的 csv 文件:

multiplicity  
4.123  
lattice parameters  
1,0,0  
0,1,0  
0,0,1  
atom sites  
0,0,0  
0.5,0.5,0.5  
occupancy  
1,0  
0,1  

我想创建一个代码,它可以自动将多重性下的行存储为变量的数据,以此类推,用于 csv 的其余部分。我不能在csv中对诸如multiplicity is line[2]之类的值进行硬编码,因为每个行的行数都会改变。我想创建一个循环,将标头之间的数据存储为变量,但我不确定如何。

理想情况下,我希望代码搜索第一个标题和第二个标题,然后将其间的值保存为多重性变量。然后我希望它找到第二个标题和第三个标题并将这些值保存为 lattice 参数。找到第三个标头和第四个标头以及它们之间的值作为原子站点。最后找到第四个标题和 csv 的结尾,并将其间的值保存为占用。

【问题讨论】:

  • 您能详细说明一下您要使用的 csv 文件吗?
  • 你的 csv 是否会包含每一行的数据??
  • 我的 csv 看起来就像问题中显示的一样。问题是每个标题下的行数会有所不同。有时它会在 atom 下有 3 个站点,有时它会有 8 个,这就是为什么我需要一个循环来自动化这个过程。
  • 理想情况下,我希望代码找到第一个字符串和之后的字符串,并将中间的行(带有数字的行)分配给一个变量,并为 csv 的每个部分执行此操作。因此,我会将多重性、晶格参数、原子位置和占用率的数据分别保存在一个变量中。
  • 理想情况下,我希望代码搜索第一个标题和第二个标题,然后将其间的值保存为多重性变量。然后我希望它找到第二个标题和第三个标题并将这些值保存为 lattice 参数。找到第三个标头和第四个标头以及它们之间的值作为原子站点。最后找到第四个标题和 csv 的结尾,并将其间的值保存为占用。

标签: python csv


【解决方案1】:

您可以尝试在collections.defaultdict() 中收集您的行。

至于将行分组到各自的标题,您似乎可以检查一行是否包含所有字母和空格,并且是csv.reader() 读取的一项。很难说,因为您只显示了数据的快照。我在下面的例子中做了这些假设。确定如何找到标题后,您可以简单地添加所有后续行,直到找到另一个标题。

我还假设您的普通行包含整数和浮点数。您可以使用ast.literal_eval() 将它们直接转换为正确的类型。

演示:

from csv import reader
from collections import defaultdict
from ast import literal_eval
from pprint import pprint

# Create a dictionary of lists
data = defaultdict(list)

# Open your file
with open('data.csv') as f:

    # Get the csv reader
    csv_reader = reader(f)

    # Initialise current header
    # If rows fall under this header, they don't have a header
    current_header = None

    # Go over each line in the csv file
    for line in csv_reader:

        # Found header
        if len(line) == 1 and all(item.isalpha() or item.isspace() for item in line[0]):
            current_header = line[0]
            continue

        #  If we get here, normal line with ints and floats
        data[current_header].append(list(map(literal_eval, line)))

pprint(data)

输出:

defaultdict(<class 'list'>,
            {'atom sites': [[0, 0, 0], [0.5, 0.5, 0.5]],
             'lattice parameters': [[1, 0, 0], [0, 1, 0], [0, 0, 1]],
             'multiplicity': [[4.123]],
             'occupancy': [[1, 0], [0, 1]]})

现在您有了一个字典,其中存储了每个标题及其各自的行。这可以稍后进行操作,并在需要时添加。

这是打印每个标题及其各自行的示例(嵌套列表):

for header, rows in data.items():
    print("Header: %s, Rows: [%s]" % (header, ",".join(map(str, rows))))

# Header: multiplicity, Rows: [[4.123]]
# Header: lattice parameters, Rows: [[1, 0, 0],[0, 1, 0],[0, 0, 1]]
# Header: atom sites, Rows: [[0, 0, 0],[0.5, 0.5, 0.5]]
# Header: occupancy, Rows: [[1, 0],[0, 1]]

您还可以查看How to use dictionaries in Python 以了解有关字典以及如何操作它们的更多信息。

【讨论】:

  • 使用defaultdict 是否可以避免检查列表是否已经存在?我认为使用常规的dict,当您尝试附加到未初始化的标头时,您的代码会抛出错误(通常您需要data[current_header] = [],然后才能appenddata[current_header]
  • @NotAnAmbiTurner 是的,defaultdict() 会为您处理。它会预先初始化一个列表,让您免于执行data[current_header] = []
  • @NotAnAmbiTurner 是的,它非常有帮助。你也可以使用d.setdefault(current_header, []).append(row)
  • 对不起,我刚刚开始使用 Python,所以我有很多问题。这是否会将值保存在我可以稍后操作的变量中,以及如何打印各个变量。
  • @Gabriela 是的。查看 RoadRunner 解决方案中的输出 - 这是一个您可以稍后操作的字典。
【解决方案2】:

我的 0.02 美元:

  • 问题中列出的方法过于复杂。您无需识别第一个和第二个标题并在其间附加数据。你需要:
    1. 一种识别您是否击中头球的方法
    2. 将适当处理标题后面的值的代码

这不是工作代码,但您可能需要来自 python csv module 的东西,可能看起来像这样(RoadRunner 的代码更完整,但我认为我们都在进行相同的行,最终会得到几乎相同的输出)。

data_dict = {}

import csv
with open('file_name.csv', newline='') as csvfile:
     csvreader = csv.reader(csvfile, delimiter=',')
     curr_header = "IF THIS IN DICT, SOMETHING IS WRONG"
     for row in csvreader:
         try: # look for header, if not header, append data
             float(row[0])
             data_dict[curr_header].append([float(x) for x in row])
         except ValueError: # found a header
             curr_header = row[0]
             data_dict[curr_header] = []

print(data_dict)

【讨论】:

    【解决方案3】:
    import re
    
    data = {}
    lines = list(open("data.csv", 'r'))
    
    for line in lines:
        check = line.split(",")[0].strip()
        if not re.match("^-?\d+\.?\d*$", check):
            key = check
        else:
            data[key] =  data.get(key, []) + [[float(x) for x in line.split(",")]]
    

    数据字典看起来像:

    {'atom sites': [[0.0, 0.0, 0.0], [0.5, 0.5, 0.5]],
     'lattice parameters': [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
     'multiplicity': [[4.123]],
     'occupancy': [[1.0, 0.0], [0.0, 1.0]]}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-10
      • 2017-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-03
      相关资源
      最近更新 更多