我正在尝试创建一个CSV阅读器,它只包含所有第6,7和8列中的读数数据。
我的数据是一年中的几天降雨量。我的代码有一个例外,但有些数据会在几天内被记录下来。记录数据的天数在row[6]
中显示,前几天在第6,7和8列中留空,即使它们已完成。
因此,对于读者,我需要制作一个计数器,首先检查数据是否完整(没有空白)或是否有空白并且是另一个读数的一部分(记录在几天内)或不完整(没有读数)我到目前为止所做的工作如下所示:
datalist = []
def read_complete_data():
''' Reads the file'''
filename = input("Enter file name:") #File must be in the same folder as the directory
with open(filename, 'r') as fileobj:
#open file for reading
reader = csv.reader(fileobj, delimiter = ',')
next(reader)
tempList = []
for row in reader:
if row[5] == "" and row[6] == "" and row[7] == "" :
tempList.append(row)
#Checks if the row is complete
elif row[5] != "" and row[6] != "" and row[7] != "":
numDay = int(row[6])
while numDay > 1:
datalist.append(tempList[1-numDay])
numDay -= 1
数据示例:
Product code, Station number, Year, Month, Day, Rainfall, Period, Quality IDCJAC0009, 70247, 1988, 12, 21, 0, , Y IDCJAC0009, 70247, 1988, 12, 22, 0, , N IDCJAC0009, 70247, 1988, 12, 23, 0.2, 1, Y IDCJAC0009, 70247, 1988, 12, 24, 0.4, 1, Y IDCJAC0009, 70247, 1988, 12, 25, , Y IDCJAC0009, 70247, 1988, 12, 26, 34.8, 2, Y IDCJAC0009, 70247, 1988, 12, 27, 30.8, 1, N
如上所述,前两个数据样本是不完整的,因为没有测量它们的周期。可以看出,第5行的数据样本是不完整的,但是下面的样本的测量周期为2意味着第5行实际上是完整的,它只是在2天的跨度而不是单日测量。这是测量2天的示例,但是有更大的示例,其中最多5天被分组到一个测量中。最后一列是数据的质量以及是否是质量检查。它必须是Y才能成为完整的数据。正如我添加的第1行和第2行仍然不完整。但是第7行现在还不完整。
输出:基本上我想要实现的是要读取的CSV文件和要从datalist中删除的不完整数据行。使用这个临时列表,我试图让datalist只包含完整的数据集。
通缉输出:
Product code, Station number, Year, Month, Day, Rainfall, Period, Quality IDCJAC0009, 70247, 1988, 12, 23, 0.2, 1, Y IDCJAC0009, 70247, 1988, 12, 24, 0.4, 1, Y IDCJAC0009, 70247, 1988, 12, 25, , Y IDCJAC0009, 70247, 1988, 12, 26, 34.8, 2, Y
使用下一个(阅读器)行,因为数据的顶行包含标题而不是实际数据。我在想我的问题是因为我如何编写for循环和while循环使用临时列表然后复制回主列表(称为datalist)。可能会有一行代码我错过了它需要它才能工作。
我知道这可能是一个非常令人困惑的问题,可能很难回答,因为这里没有给出数据,但是我的代码和读取CSV文件可能出错的任何帮助都非常感谢。我想我会把问题提到这里,即使解释起来也很困惑。 感谢
答案 0 :(得分:2)
CSV读取器是Python中的生成器这意味着它们不会比预期读取更多,这是有效的,因为它不需要先将整个CSV存储在内存中。
保持生成器语义并编写一个包含CSV读取器的小型过滤器函数并在运行中更改它的输出是有意义的。
要求是:
在下文中,filter_rainfall_data
是一个生成器函数(生成器使用yield
而不是return
),它对需求#1有一点缓冲,而不是yield
任何要求#2。
import csv
def filter_rainfall_data(filename):
with open(filename, 'r', encoding='UTF-8', newline='') as rows:
reader = csv.reader(rows, delimiter=',')
# yield header row
yield next(reader)
buffer = []
for row in reader:
# strip whitespace from all values
row = list(map(str.strip, row))
# any row without read-outs is stored in a buffer
if row[5] == "" and row[6] == "":
buffer.append(row)
continue
# any row with proper read-outs is yielded
if row[5] > "" and row[6] > "":
days = int(row[6])
# yield all previously buffered rows, if necessary
yield from buffer[-days - 1:]
# finally yield the current row itself
yield row
buffer = []
用法如下:
filename = input("Enter file name:")
for row in filter_rainfall_data(filename):
print(row)
使用您的示例输入为我打印
['Productcode', 'Stationnumber', 'Year', 'Month', 'Day', 'Rainfall', 'Period', 'Quality']
['IDCJAC0009', '70247', '1988', '12', '23', '0.2', '1', 'Y']
['IDCJAC0009', '70247', '1988', '12', '24', '0.4', '1', 'Y']
['IDCJAC0009', '70247', '1988', '12', '25', '', '', 'Y']
['IDCJAC0009', '70247', '1988', '12', '26', '34.8', '2', 'Y']
['IDCJAC0009', '70247', '1988', '12', '27', '30.8', '1', 'N']
如果需要,您可以使用CSV编辑器将其转换为新的CSV文件。
注意:
buffer[-days - 1:]
列出缓冲区中最后N行的一部分。当Period
为5天时,buffer[-days - 1:]
将获得最后4个缓冲行。days = int(row[6])
将因非数字值而失败。yield from
已在Python 3.3中引入。请参阅How to Pythonically yield all values from a list? encoding
参数。newline=''
。请参阅Footnotes in the csv module documentation。