如何读取csv文件至特定行并将其存储在变量中

时间:2018-11-19 04:55:33

标签: python csv

我想读取一个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中将诸如multiplicity之类的值硬编码为line [2],因为每行的行数都会改变。我想创建一个循环,该循环将标头之间的数据存储为变量,但是我不确定该怎么做。

理想情况下,我希望代码搜索第一个标头和第二个标头,然后将两者之间的值另存为多重性变量。然后,我希望它找到第二个标头和第三个标头,并将这些值另存为晶格参数。找到第三个标头和第四个标头及其之间的值作为原子位点。最后找到第四个标头和csv的末尾,并将中间的值保存为占用率。

3 个答案:

答案 0 :(得分:2)

您可以尝试将行收集到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,以了解有关字典以及如何操作它们的更多信息。

答案 1 :(得分: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)

答案 2 :(得分:1)

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]]}