在Python中从CSV文件中删除特定行

4
我正在尝试从一个大型CSV文件中删除特定日期范围内具有特定ID的行。
CSV文件包含一个格式为“1962-05-23”的日期列[3]和一个带有标识符[2]的列:“ddd:011232700:mpeg21:a00191”。
在以下日期范围内:
01-01-1951至12-31-1951
07-01-1962至12-31-1962
01-01至09-30-1963
7-01至07-31-1965
10-01至10-31-1965
04-01-1966至11-30-1966
01-01-1969至12-31-1969
01-01-1970至12-31-1989
我想要删除包含ID ddd:11 *的行。
我认为我必须创建一个包含日期范围和ID的变量,并在每一行中查找它们,但我对Python非常陌生,所以我不确定如何优雅地完成这项任务。
这是我现在拥有的代码。-代码已更新
import csv
import collections
import sys
import re
from datetime import datetime

csv.field_size_limit(sys.maxsize)

dateranges = [("01-01-1951","12-31-1951"),("07-01-1962","12-31-1962")]
dateranges = list(map(lambda dr: tuple(map(lambda x: datetime.strptime(x,"%m-%d-%Y"),dr)),dateranges))


def datefilter(x):
    x = datetime.strptime(x,"%Y-%m-%d")
    for r in dateranges:
        if r[0]<=x and r[1]>=x: return True
    return False

writer = csv.writer(open('filtered.csv', 'wb'))
for row in csv.reader('my_file.csv', delimiter='\t'):
    if datefilter(row[3]):
        if not row[2].startswith("dd:111"):
            writer.writerow(row) 
    else: 
        writer.writerow(row)
writer.close()

你可以创建一个“列表”,其中包含符合你的条件的特定字段,然后将其写入文件。上述代码有什么问题? - Nikhil Parmar
你可以使用正则表达式来匹配 id - Nikhil Parmar
我只是不确定如何完成它。基本上,如何制作日期列表?如何写回原始文件。对于ID,我会管理。 - Melvin Wevers
1
请给我一个样本集,并在此处或提供任何样本链接。 - Nikhil Parmar
1
@NikhilParmar 这是一个样本集:https://dl.dropboxusercontent.com/u/279252/mwevers_example_2016.01.02-07.25.55.csv -- 这个文件中可能不包含所有日期(为了保持文件较小)。 - Melvin Wevers
4个回答

2
我建议使用 pandas:它非常适合过滤表格。易于阅读。
import pandas as pd

# assumes the csv contains a header, and the 2 columns of interest are labeled "mydate" and "identifier"
# Note that "date" is a pandas keyword so not wise to use for column names
df = pd.read_csv(inputFilename, parse_dates=[2])  # assumes mydate column is the 3rd column (0-based)

df = df[~df.identifier.str.contains('ddd:11')]  # filters out all rows with 'ddd:11' in the 'identifier' column
# then filter out anything not inside the specified date ranges:
df = df[((pd.to_datetime("1951-01-01") <= df.mydate) & (df.mydate <= pd.to_datetime("1951-12-31"))) |
        ((pd.to_datetime("1962-07-01") <= df.mydate) & (df.mydate <= pd.to_datetime("1962-12-31")))]

df.to_csv(outputFilename)

请查看Pandas布尔索引

1

以下是我处理此问题的方式,但可能不是最佳方法。

from datetime import datetime
dateranges = [("01-01-1951","12-31-1951"),("07-01-1962","12-31-1962")]
dateranges = list(map(lambda dr: tuple(map(lambda x: datetime.strptime(x,"%m-%d-%Y"),dr)),dateranges))

def datefilter(x):
    # The date format is different here to match the format of the csv
    x = datetime.strptime(x,"%Y-%m-%d")
    for r in dateranges:
        if r[0]<=x and r[1]>=x: return True
    return False

with open(main_file, "rb") as fp:
    root = csv.reader(fp, delimiter='\t')
    result = collections.defaultdict(list)
    for row in root:
        if datefilter(row[3]):
            # use a regular expression or any other means to filter on id here
            if row[2].startswith("dd:111"): #code to remove item

我所做的是创建一个日期范围的元组列表(为简洁起见,我只放了2个范围),然后将其转换为datetime对象。
我使用了映射来在一行中完成这个操作:首先循环遍历该列表中的所有元组,应用一个函数,该函数循环遍历该元组中的所有条目并将其转换为日期时间,使用元组和列表函数返回原始结构。如果按照长方式进行,它看起来像这样:
dateranges2=[]
for dr in dateranges:
    dateranges2.append((datetime.strptime(dr[0],"%m-%d-%Y"),datetime.strptime(dr[1],"%m-%d-%Y"))
dateranges = dateranges2

注意,我只是将元组中的每个项目转换为datetime,并将这些元组添加到新列表中,替换原始列表(我不再需要它)。
接下来,我创建了一个datefilter函数,它接受一个日期字符串,将其转换为datetime,然后循环遍历所有范围,检查该值是否在范围内。如果是,则返回True(表示应该过滤此项),否则返回False,如果我们已经检查了所有范围但没有匹配项(表示我们不过滤此项)。
现在你可以使用任何你想要的方法检查id是否匹配日期,并在需要时删除该项。由于你的示例在前几个字符中是常量,因此我们可以使用字符串startswith函数来检查id。如果更复杂,我们可以使用正则表达式。

1
我已经修改了函数以匹配csv格式。请注意,datefilter函数中使用的日期格式应与csv相匹配。处理范围列表所使用的格式应与您的范围规格相匹配。 - Matthew
@Matthew。我遇到了一个列表索引超出范围的错误。我认为这是因为我想要过滤的日期列表并不总是在我使用的文件中。有时我会在此范围内使用特定的时间段。我该如何解决这个问题? - Melvin Wevers
1
你在哪里遇到了错误?看起来你提供的CSV文件链接现在无法使用,所以我无法根据你的实际文件进行测试。你的某些行是否缺少一些字段?如果某些行少于4个字段(即没有日期或ID),访问row [2]和row [3]将导致该错误。 - Matthew
文件应该再次上线:https://www.dropbox.com/s/ue976gk34qkj2ch/my_file.csv?dl=0 - Melvin Wevers
问题出在你创建csvreader的地方。它期望一个文件而不是一个文件名。将for row in csv.reader('my_file.csv', delimiter='\t')改为for row in csv.reader(open('my_file.csv','r'), delimiter='\t') - Matthew

0

我的方法是这样的 -

import csv 
import re
import datetime

field_id = 'ddd:11'




d1 = datetime.date(1951,1,01) #change the start date
d2 = datetime.date(1951,12,31) #change the end date
diff = d2 - d1
date_list = []
for i in range(diff.days + 1):
    date_list.append((d1 + datetime.timedelta(i)).isoformat())
with open('mwevers_example_2016.01.02-07.25.55.csv','rb') as csv_file:

    reader = csv.reader(csv_file)

    for row in reader:

        for date in date_list:
            if row[3] == date:
                print row
                var = re.search('\\b'+field_id,row[2])
                if bool(var) == True:

                    print 'olalala'#here you can make a function to copy those rows into another file or any list

感谢您的帮助。我会尝试使用ID过滤器并输出来看看它能否正常工作。 - Melvin Wevers

0
import csv
import sys
import re
from datetime import datetime

csv.field_size_limit(sys.maxsize)

field_id = 'ddd:11'

dateranges = [("1951-01-01", "1951-12-31"),
              ("1962-07-01", "1962-12-31"),
              ("1963-01-01", "1963-09-30"),
              ("1965-07-01", "1965-07-30"),
              ("1965-10-01", "1965-10-31"),
              ("1966-04-01", "1966-11-30"),
              ("1969-01-01", "1989-12-31")
              ]
dateranges = list(map(lambda dr:
                      tuple(map(lambda x:
                            datetime.strptime(x, "%Y-%m-%d"), dr)),
                      dateranges))


def datefilter(x):
    x = datetime.strptime(x, "%Y-%m-%d")
    for r in dateranges:
        if r[0] <= x and r[1] >= x:
            return True
    return False


output = []
with open('my_file.csv', 'r') as f:
    reader = csv.reader(f, delimiter='\t', quotechar='"')
    next(reader)
    for row in reader:
        if datefilter(row[4]):
            var = re.search('\\b'+field_id, row[3])
            if bool(var) == False:
                output.append(row)
        else:
            output.append(row)


with open('output.csv', 'w') as outputfile:
    writer = csv.writer(outputfile, delimiter='\t', quotechar='"')
    writer.writerows(output)

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