对CSV中的无效行进行故障排除

我正在处理一个非常大的CSV文件(将近6 GB),并且绝对有很多错误。例如,如果我有以下csv文件/表:

+------------+-------------+------------+
|     ID     |    Date     |   String   |
+------------+-------------+------------+
|  123456    |  09-20-2019 |   ABCDEFG  |
|  123abc456 |  10-30-2019 |   HIJKLMN  |
|  7891011   |  jdqhouehwf |   OPQRSTU  |
|  1010101   |  03-15-2018 |   8473737  |
|  4823.00   |  02-11-2015 |   VWXYZ    |
|  2348813.0 |  01-23-2016 |   BAZ      |
+------------+-------------+------------+

或:

"ID","Date","String"
123456,"09-20-2019","ABCDEFG"
123abc456,"10-30-2019","HIJKLMN"
7891011,"jdqhouehwf","OPQRSTU"
1010101,"03-15-2018",8473737
4823.00,"02-11-2015","VWXYZ"
"2348813.0","01-23-2016","BAZ"

我想要一种排除故障并修复文件的好方法。使用熊猫,我可以读取文件:

import pandas as pd

df = pd.read_csv(inputfile)

熊猫总是会抱怨: sys:1: DtypeWarning: Columns (0) have mixed types. Specify dtype option on import or set low_memory=False

所以我想清理每一列。但是由于它是一个很大的文件,所以我不能只打印整个表以带遮罩输出并期望读取它。我想要一种简单的方法来获取列并检查其是否符合类型。另外,如果可能的话,我想要一种删除不良行和/或将行转换为正确格式的方法。说完一切之后,我希望文件看起来像(不包括嵌入式注释):

"ID","ABCDEFG"
#  123abc456,"HIJKLMN" was deleted because the ID wasn't a number
#  7891011,"OPQRSTU" was deleted because the data was not a date
1010101,"8473737" # The last number could be converted to string
4823,"VWXYZ" # The first number could be converted to integer
2348813,"BAZ" # The ID number could be converted to int
h00309110 回答:对CSV中的无效行进行故障排除

def main():

    from pathlib import Path
    import csv
    import datetime as dt

    with Path("thing.csv").open("r") as file:
        for row in csv.DictReader(file):
            try:
                row["ID"] = int(float(row["ID"]))
                row["Date"] = dt.datetime.strptime(row["Date"],"%m-%d-%Y")
            except (KeyError,ValueError):
                continue
            print(*row.values())

    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main())
,

标记了sed时,这是一条应该以非常有效且可移植的方式完成此工作的命令,但这有点难以理解...

sed -n '1p;s/^"\{0,1\}\([0-9]\+\)\(\.[0-9]*\)\{0,1\}"\{0,1\}\(,"\(0[0-9]\|1[0-2]\)-\([0-2][0-9]\|3[01]\)-2[0-9]\{3\}",\)"\{0,1\}\([^"]*\)"\{0,1\}$/\1\3"\6"/p' file

它的作用是:

  1. 打印标题,即第一行(1p),
  2. 在所有行上尝试一个替换(s)命令,并仅在替换成功(并且因此仅在该行与搜索模式匹配的情况下)s/…/…/p时打印结果。

关于替代模式\1\3"\6",每个转义数字都指对应的捕获组(\(…\);请记住,根据开头{{1} }令牌出现)。具体来说:

  1. \(指的是前导数字(\1),带有或不带有([0-9]\+)的以下三件事:

    • 领先的\{0,1\}
    • 结尾的小数部分"
    • 以及以下\.[0-9]*;
  2. "是指包含\3在内的日期("请注意,我在此正则表达式中并不准确,因为它也会匹配非正则表达式-现有日期,例如2月31日);

  3. "\(0[0-9]\|1[0-2]\)-\([0-2][0-9]\|3[01]\)-2[0-9]\{3\}"指向(并放在"\6"之间)最后一个字母数字字符串,我几乎没有做任何假设(")。

这应该更好地匹配日期(除了2月29日总是匹配,而不考虑年份)

[^"]*
本文链接:https://www.f2er.com/3093677.html

大家都在问