【问题标题】:For Loop across Multiple Folders to Resample Datetime in Multiple CSV Files and Export with File Name Automatically GeneratedFor 循环跨多个文件夹以在多个 CSV 文件中重新采样日期时间并使用自动生成的文件名导出
【发布时间】:2017-04-05 22:49:39
【问题描述】:

我有许多数据框(csv 文件)位于我计算机上文档的各个文件夹中。所有 csv 文件具有相同数量的列,其中每列的名称相同且顺序相同,但是文件中存在不同数量的数据行。所有文件的第一列都有“日期时间”,其中“YYYYMMDD HH:MM:SS”记录在数据行的下方。

我想对所有数据框重新采样,以从原始文件中创建每小时、每天和每月的数据。 csv 文件中的某些列要求对小时、天和月的数据求和,而其他列需要对这些时间范围内的数据进行平均(在所有 csv 文件中保持一致)。我希望每个原始 csv 文件都有自己的每小时、每天和每月版本。

所有 csv 文件都存在于以下输入路径中,但实际上位于此输入路径中的其他文件中:

inputpath = 'C:/Users/cp_vm/Documents/Data/Input/Clean/'

例如,在“Clean”文件夹中还有两个文件夹,在这些文件夹中还有其他包含所有 csv 文件的文件夹。我想读取存在于“Clean”文件夹之后的所有 csv 文件,而不必编写多个“输入路径”并重新采样前面提到的文件。

然后我想将这些重新采样的数据帧导出到它们来自的文件夹中,并在它们的名称中添加“小时”、“日”或“月”。

下面提供了 csv 文件的 sn-p 示例。

例如,我想将 15 分钟间隔数据重新采样为每小时、每天和每月数据。重新采样时,前两列需要求和,而第三列需要在重新采样的时间范围内进行平均。我知道 df.resample('h').sum() 将对一小时内的数据求和, *.mean() 将对一小时内的数据进行平均,但是当不同的列需要不同的重采样然后想要将所有这些列组合在一起,然后将每小时、每天或每月文件导出到其文件名已自动更改为每小时、每天或每月的相应位置。

我意识到这是非常具有描述性的,但它会导致我出现各种延迟,并且重新定位 csv 文件会影响我已经编写的另一个 python 脚本。任何建议将不胜感激。提前感谢您提供的任何帮助。

【问题讨论】:

    标签: python csv datetime export-to-csv


    【解决方案1】:

    很难找出你的问题到底出在哪里:)

    但是python有类似os.walk的东西,我给你举个例子:

    import os
    
    root_directory = '/home/xyz/some_root_dir/'
    
    def is_csv(fname):
        return fname.endswith('.csv')
    
    csv_files = []
    
    for directory, subdirectories, files_names in os.walk(root_directory):
        for fname in files_names:
            if is_csv(fname):
                csv_files.append(
                    {
                        'directory': directory,
                        'fname': fname
                    }
                )
    
    print(csv_files)
    

    这在我的测试用例中:

    [
        {'directory': '/home/xyz/some_root_dir', 'fname': 'my.csv'},
        {'directory': '/home/xyz/some_root_dir/test2/test31', 'fname': 'myohter3.csv'}
        {'directory': '/home/xyz/some_root_dir/test2/test31', 'fname': 'myohter.csv'}
    ]
    

    这肯定会帮助您获取所有 csv 文件 - 您可以根据需要修改 is_csv 方法。我无法帮助您汇总数据:)

    但是一旦你阅读了所有的数据,这应该不是什么大问题。

    好的,现在开始有趣了。我做的很快 - 可能可以写得更好,但这是一个很好的起点,我们有上一步的文件列表,让我们进行下一步:

    import csv
    import os
    from datetime import datetime
    
    data = {}
    
    # gather the data;
    for fdata in csv_files:
        with open(os.path.join(fdata['directory'], fdata['fname']), 'r') as f:
            reader = csv.reader(f, delimiter='|', quotechar='"')
            rows = list(reader)
            data[fdata['fname']] = rows  # we can't store it per datetime here, because can lost data
    
    # ok we have a data now in format:
    
    # {
    #     'other3.csv': [
    #         ['Datetime', 'Egen1_NotCum_kWh', 'Egen2_NotCum_kWh', 'Egen3_NotCum_kWh'],
    #         ['2016-09-04 13:45:00', '643.23', '649', '654'],
    #         ['2016-09-04 14:00:00', '612.21', '672', '666'],
    #         ['2016-09-04 14:15:00', '721.3', '719', '719'],
    #         ['2016-09-04 14:30:00', '730', '721', '725'],
    #         ['2016-09-04 14:45:00', '745', '725', '731']],
    #     'my.csv': ...
    # }
    
    # convert the string data to python Datetime
    
    DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
    
    for fname, inner_data in data.iteritems():
        for row in inner_data[1:]:  # skip headers
            p_datetime = datetime.strptime(row[0], DATETIME_FORMAT)
            row[0] = p_datetime
    
    # now the aggregates;
    
    def get_all_rows_in_dates(start_date, end_date, data):
        headers = data[data.keys()[0]][0]
        data_rows = []
        for fname, inner_data in data.iteritems():
            for row in inner_data[1:]:  # skip the header
                if start_date <= row[0] < end_date:
                    data_rows.append(row)
    
        return headers, data_rows
    
    def aggregate_col_12(values):
        values  = map(float, values)
        return sum(values)
    
    def aggregate_col_3(values):
        values  = map(float, values)
        return sum(values) / float(len(values))
    
    def count_aggregates(rows_in_dates, start_date):
        col1 = []
        col2 = []
        col3 = []
        for row in rows_in_dates[1:]:  # skip headers
            col1.append(row[1])
            col2.append(row[2])
            col3.append(row[3])
        return [start_date.strftime(DATETIME_FORMAT),
            aggregate_col_12(col1), aggregate_col_12(col2), aggregate_col_3(col3)]
    
    
    def write_results(headers, aggregate, fname):
        data = []
        data.append(headers)
        data.append(aggregate)
        with open(fname, 'w+') as f:
            writer = csv.writer(f, delimiter='|', quotechar='"', quoting=csv.QUOTE_MINIMAL)
            writer.writerows(data)
    
    
    start_date = datetime(2016, 9, 4, 13, 0, 0)
    end_date = datetime(2016, 9, 4, 14, 0, 0)
    
    headers, to_aggregate = get_all_rows_in_dates(
        start_date,
        end_date,
        data)
    
    aggregates = count_aggregates(to_aggregate, start_date)
    write_results(headers, aggregates, 'from_{}_to_{}.csv'.format(
        start_date.strftime(DATETIME_FORMAT),
        end_date.strftime(DATETIME_FORMAT),
    ))
    

    请注意 - 在您的代码中使用适当的分隔符和引号字符。 而这才刚刚开始——您可以将其用作开始——每日汇总——应该可以通过这段代码实现,但如果你想要一个小时的每秒行的 csv——你需要稍微包装一下。

    如果您有任何问题 - 请做。

    【讨论】:

    • 谢谢@SebastianOpalczyński - 当我打印(csv_files)时,我得到了我的 88 个 csv 文件的列表,这很棒。但我想要的是能够重新采样所有 88 个文件,使其每个都有自己的每小时、每天和每月版本,因为它们每个都有“日期时间”作为他们的第一列。有些列需要求和,而另一些则需要在重采样时间范围内取平均值。
    猜你喜欢
    • 2017-04-08
    • 1970-01-01
    • 1970-01-01
    • 2019-04-09
    • 1970-01-01
    • 2021-01-22
    • 2019-08-04
    • 2023-03-25
    • 2013-06-22
    相关资源
    最近更新 更多