Python CSV阅读器检查完整数据

3

我正在尝试创建一个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

数据示例:

产品代码,站点编号,年份,月份,日期,降雨量,周期,质量
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天的示例,但是还有更大的示例,其中最多将5天分组为一次测量。最后一列是数据的质量和是否进行质量检查。它需要是Y以获得完整数据。如我所补充的,第1行和第2行仍然不完整。但是第7行现在也不完整。

输出:基本上我想要实现的是读取CSV文件并从数据列表中删除不完整的数据行。使用这个临时列表,我试图使数据列表只包含完整的数据集。

期望的输出:

产品代码,站点编号,年份,月份,日期,降雨量,周期,质量
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 

下一个(reader)行用于读取数据的标题而不是实际数据。我认为问题出在我如何编写for循环和while循环的方式上,使用一个临时列表,然后将其复制回主列表(称为datalist)。可能有一行代码我漏掉了,需要它才能正常工作。

我知道这可能是一个非常令人困惑的问题,因为这里没有给出数据,但我非常感谢能够帮助我找出我的代码和读取CSV文件中可能有什么问题。虽然很难解释清楚,但我还是把问题发到了这里。


1
你的问题如果能提供一个代表性的输入示例和你想要生成的匹配输出,将会大大有助于解答。虽然用英语描述也很好,但实际上看到示例更好。 - undefined
1
谢谢提供的示例,但是那里的行没有8列。而且你的代码显示你的输入是逗号分隔的,但是你的示例不是。你想要看到的输出也没有给出。 - undefined
抱歉,我删除了与此部分无关的行,我正在尝试查找。它们包括产品代码和站点编号。我会添加最后一列,我忘记了,我的错。 - undefined
1
请展示实际数据...否则delimiter = ','显然是错误的...逗号在哪里? - undefined
你对那个示例的预期输出仍然没有理解。我已经说了三次了。如果有人想提供一个解决方案,他们需要一些可行的输入来进行操作 - 他们可以复制粘贴到自己的电脑上 - 并且需要一个期望的结果来与他们的解决方案进行比较。 - undefined
显示剩余4条评论
1个回答

4

CSV读取器是Python中的生成器。这意味着它们不会超前读取更多内容,这很高效,因为没有必要先将整个CSV存储在内存中。

保持生成器语义并编写一个小的过滤函数来包装CSV读取器,并即时更改其输出是有意义的。

要求如下:

  1. 如果当前行中没有读取值(降雨量,周期),则将其保留,直到下一行具有读取值。
  2. 如果一行似乎无效,则根本不输出它。

在下面的代码中,filter_rainfall_data是一个生成器函数(生成器使用yield而不是return),它有一个小缓冲区用于需求#1,并且对于需求#2根本不yield任何东西。

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天时,《code>buffer[-days - 1:] 将获取最后4个缓冲行。 - int(row[6]) 将无法处理非数字值。 - 在Python 3.3中引入了yield from。请参阅 如何以Python方式从列表中产出所有值? - 打开文本文件时,应始终提供encoding参数。 - 打开CSV文件时,应始终设置newline=''。请参阅csv模块文档中的脚注

这几乎完美!我可能会做一些小调整,但这正是我想要的!非常感谢你! - undefined
它紧密遵循了你代码背后的思想,只需稍微调整缩进,就能使你的代码正常运行。你做的一切都是正确的,只是时间上稍微有些不对。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接