Объединение нескольких файлов по годам (столбец в данных) в одну строку и добавление имени файла в качестве первого столбца на Perl или Python

Вопрос или проблема

У меня есть более 3000 файлов, которые нужно объединить на основе конкретных атрибутов в файлах. Например, каждый файл назван по своему ID (например, 101567AD_Mly.txt). Эти ID соответствуют значениям широты и долготы, которые я добавлю к файлу позже. Мне нужно добавить ведущий столбец в каждый выходной файл с ID. Затем я хотел бы объединить строки во входных файлах так, чтобы вывод выглядел как ИДЕНТИФИКАЦИЯ, ГОД, КОД МЕСЯЦА ЯНВАРЯ (1), ЯНВАРЬ ОСАДКИ, КОД МЕСЯЦА ФЕВРАЛЯ (2), ФЕВРАЛЬ ОСАДКИ, КОД МЕСЯЦА МАРТА (3), МАРТ ОСАДКИ……
В настоящее время файлы разделяют каждый месяц на новую строку, как в примере ниже, где структурировано как ГОД, МЕСЯЦ, НЕИЗВЕСТНОЕ ЗНАЧЕНИЕ, СУММА ОСАДКИ. Я хотел бы объединить более 3000 файлов на основе ID для каждого, который является их именем файла. В идеале, у меня был бы файл для каждого года данных (1979, 1980, 1981 и т. д.), чтобы все файлы с данными за эти годы (например, 1981) были бы в одном файле, где каждая строка представляет собой другой ID. Имена файлов описывают идентификацию того, откуда эти данные пришли, так что я хотел бы, чтобы это было ведущим столбцом в каждом файле.
Вот пример того, как выглядят файлы:

ГОД, МЕСЯЦ, УДАЛИТЬ ТРЕТИЙ СТОЛБЕЦ, СУММА ОСАДКИ
1980 1 0 112.106
1980 2 0 131.909
1980 3 0 58.842
1980 4 0 42.075
1980 5 0 45.268
1980 6 0 126.168
1980 7 0 30.159
1980 8 0 32.168
1980 9 0 39.48
1980 10 0 46.117
1980 11 0 234.089
1980 12 0 180.227
1981 1 0 62.795
1981 2 0 131.817
1981 3 0 73.429
1981 4 0 77.282
1981 5 0 54.224
1981 6 0 81.217
1981 7 0 18.469
1981 8 0 12.695
1981 9 0 83.4
1981 10 0 130.957
1981 11 0 151.07
1981 12 0 190.582
1982 1 0 210.604
1982 2 0 143.732
1982 3 0 26.124
1982 4 0 45.952
1982 5 0 10.38
1982 6 0 33.602
1982 7 0 42.218
1982 8 0 9.541
1982 9 0 39.356
1982 10 0 87.037

Третий столбец можно просто удалить.
Любая помощь по объединению всего этого с использованием Perl или Python была бы замечательной. Либо однострочный код, либо скрипт. Я использую Linux для этого.

Парень, который раньше занимался этой работой и основывал все вокруг Perl, ушел на пенсию, оставив много пробелов в передаче знаний. Я затрудняюсь собрать все это воедино.

Формат вывода должен выглядеть так:

ИДЕНТИФИКАЦИЯ, ГОД, КОД МЕСЯЦА, ОСАДКИ ЗА ЭТОТ МЕСЯЦ
ADB103884_Mly, 1989, 1, 123.56, 2, 56.23, 3, 58.9, 4, -99.99, 5, 6.9, 6, 48.2, 7, 89,1, 8, 85.3, 9, 98.1, 10, 190.2, 11, 283.9, 12, -99.99

Выходной файл можно назвать year_mly.txt

Если есть отсутствующие значения для конкретного месяца, им должно быть присвоено значение -99.99. Таким образом, у каждого ID есть значение для каждого месяца указанного года.

Я создал поддельные входные данные, как это:

#!/usr/bin/perl
use warnings;
use strict;
for my $id ('aaa' .. 'eod') {
    open my $out, '>', "file.$id" or die "file.$id: $!";
    for my $year (1979 .. 2023) {
        for my $month (1 .. 12) {
            printf {$out} "%d %d 0 %f\n", $year, $month, rand() / (1 + rand);
        }
    }
}

А затем обработал их с помощью следующего Perl-скрипта:

#!/usr/bin/perl
use warnings;
use strict;
use feature 'say';

my %by_year;

for my $file (glob 'file.???') {
    my $id = substr $file, -3;
    open my $in, '<', $file or die "$file: $!";
    while (my $line = <$in>) {
        my ($year, $month, undef, $precipitation) = split ' ', $line;
        die "Дублирование $id $year $month" if exists $by_year{$year}{$id}{$month};
        $by_year{$year}{$id}{$month} = $precipitation;
    }
}

for my $year (keys %by_year) {
    open my $out, '>', "$year.out" or die "$year.out: $!";
    for my $id (sort keys %{ $by_year{$year} }) {
        say {$out} join ' ', $id, map { $_, $by_year{$year}{$id}{$_} } 1 .. 12;
    }
}

Вы не показали, как именно названы ваши файлы, поэтому вам нужно будет настроить строку, которая делает glob, а также ту, которая извлекает id (используя substr здесь).

Ответ или решение

Для обработки множества файлов в вашей ситуации рекомендуется использовать язык Python, который обеспечивает простоту работы с файлами и манипуляцию данными. Ниже представлен детализированный код, который решает поставленную задачу.

Описание решения на Python

  1. Импорт библиотек: Сначала импортируем необходимые библиотеки.
  2. Сбор данных: Считываем данные из всех файлов, фильтруем их по годам, собираем в структуре данных.
  3. Обработка данных: Каждый файл читается, данные добавляются в структуру по годам, при этом исключается ненужный столбец.
  4. Запись выходного файла: Создание выходного файла для каждого года с необходимым форматом данных.

Код на Python

import os
import pandas as pd

# Шаг 1: Создаем словарь для хранения данных
data_by_year = {}

# Шаг 2: Обрабатываем все файлы в текущем каталоге
for filename in os.listdir('.'):
    if filename.endswith('.txt'):
        identification = filename.split('_')[0]  # Извлекаем ID из имени файла
        df = pd.read_csv(filename, delim_whitespace=True, header=None, 
                         names=["YEAR", "MONTH", "REMOVE", "PRECIPITATION"])
        df = df.drop(columns=["REMOVE"])  # Удаляем третий столбец

        # Группируем данные по годам и месяцам
        for _, row in df.iterrows():
            year = row['YEAR']
            month = row['MONTH']
            precipitation = row['PRECIPITATION']

            # Инициализируем год, если его еще нет в словаре
            if year not in data_by_year:
                data_by_year[year] = {}

            if identification not in data_by_year[year]:
                data_by_year[year][identification] = {month: precipitation}
            else:
                data_by_year[year][identification][month] = precipitation

# Шаг 3: Создаем выходные файлы для каждого года
for year, ids in data_by_year.items():
    output_filename = f"{year}_mly.txt"
    with open(output_filename, 'w') as outfile:
        for identification, months in ids.items():
            # Формируем строку с данными
            row = [identification, year]
            for month in range(1, 13):
                precipitation = months.get(month, -99.99)  # Используем -99.99 для отсутствующих значений
                row.append(month)
                row.append(precipitation)

            outfile.write(', '.join(map(str, row)) + '\n')

print("Объединение файлов и создание выходных файлов завершено.")

Пояснение к коду

  • Импортируем нужные библиотеки: os позволяет работать с файловой системой, а pandas облегчает обработку данных в табличной форме.
  • Чтение данных: Используем pd.read_csv() для чтения файлов, разделенных пробелами. Указываем названия столбцов для лучшей читаемости.
  • Группировка данных: Создаем вложенные словари для организации данных по годам и идентификациям (ID), где месяцы являются ключами.
  • Формирование выходного файла: Для каждого года создаем отдельный файл и записываем данные в требуемом формате, при этом добавляем -99.99 для отсутствующих значений.

Заключение

Приведенный выше код позволит вам эффективно объединить данные из ваших множества файлов, структурировать их по годам и идентификаторам, а также стандартизировать вывод. Убедитесь, что соответствующие библиотеки установлены в вашей среде (возможно, с помощью pip install pandas).

Данный подход позволит оптимизировать процесс и ускорить работу с большими объемами данных.

Оцените материал
Добавить комментарий

Капча загружается...