Объедините 2 CSV-файла на основе совпадения в столбце, не учитывая строку заголовка

Я искал ole interweb для этого решения, но не нашел ничего успешного. У меня есть вывод CSV из одного скрипта, который имеет данные, представленные определенным образом, и мне нужно сопоставить это и объединить с другим файлом. Дополнительный бонус, если я могу округлить до простых 2-х десятичных баллов.

Файл 1: dataset1.csv (используя столбец 1 в качестве первичного ключа или то, что я хочу найти в другом файле.)

5033db62b38f86605f0baeccae5e6cbc,20.875,20.625,41.5
5033d9951846c1841437b437f5a97f0a,3.3529411764705882,12.4117647058823529,13.7647058823529412
50335ab3ab5411f88b77900736338bc6,6.625,1.0625,3
5033db62b38f86605f0baeccae5e6cbc,2.9375,1,1.4375

Файл 2: dataset2.csv (если столбец 2 совпадает со столбцом 1 в столбце соединения файлов 1 из файла 2, заменяя данные в столбце 1 файла 1.)

"dc2","5033db62b38f86605f0baeccae5e6cbc""dc1","5033d9951846c1841437b437f5a97f0a"

Желаемые результаты:

Файл 1 (или новый файл3):

dc1,3.35,12.41,13.76
dc2,20.875,20.625,41.5

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

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

join -o 1.1,1.2,1.3,1.4,2.3 file 1 file 2 и т.д. Я проверил это несколькими различными способами. Я прочитал в ряде сообщений, что результаты должны быть отсортированы — с такой длинной строкой это немного сложно. Не говоря уже о том, что в файле 1 может быть от 30 до 40 записей, но в файле 2 может быть только 10. Мне просто нужно имя, связанное с длинной строкой.

Я начал смотреть на grep — но тогда мне понадобится цикл forEach для циклического просмотра всех результатов, и должен быть более простой способ.

Я также посмотрел на AWK — теперь это забавная попытка выяснить, как именно это сделать.

awk 'FNR==NR {a[$2]; next} $2 in a' file.csv testfile2.csv

Да … попробовал много способов сравнить это, так как это, кажется, общая идея … но все еще не заставил ее работать. Я хотел бы, чтобы это был некоторый тип сценария оболочки для linux, который будет очень простым, и что-то, что я могу вызвать со страницы php и запустить его. Например, если пользователь нажимает «Обновить», он обрабатывает данные и переваривает данные.

Любая помощь будет принята с благодарностью!

Спасибо.

к.

0

Решение

Вы можете использовать комбинацию sort и gnu awk:

mergef.awk:

BEGIN   { FS= "[ ,\"]+"; }
FNR == NR { if ( !($1 in vals) ) vals [ $1 ] = sprintf("%.2f,%.2f,%.2f", $2, $3,$4) ;}
FNR != NR { print $2 "," vals[ $3 ]; }

Скажем, ваши файлы f1.csv и f2.csv, затем используйте эту команду:

awk -f mergef.awk f1.csv f2.csv | sort
  • первая строка в скрипте имеет дело с кавычками, присутствующими во втором файле (из-за этого параметра есть пустое поле $1 для второго файла)
  • вторая строка читается в первом файле. if заботится о том, чтобы использовался только первый случай нажатия клавиши.
  • последняя строка печатает новый ключи из второго файла вдоль сохраненных значений из первого файла, извлеченных с помощью старые ключи
  • FNR == NR верно для первого файла
1

Другие решения

С помощью python и pandas библиотека:

import pandas as pd

# Read in the csv files.
df1 = pd.read_csv(dataset1.csv, header=None, index_col=0)
df2 = pd.read_csv(dataset2.csv, header=None, index_col=1)

# Round values in the first file to two decimal places.
df1 = df1.round(2)

# Merge the two files.
df3 = pd.merge(df2, df1, how='inner', left_index=True, right_index=True)

# Write the output.
df3.to_csv(output.csv, index=False, header=False)
1

кроме форматирования чисел это делает работу

$ join -t, -1 1 -2 2 -o2.1,1.2,1.3,1.4 <(sort file1) <(tr -d '"' <file2 | sort -t, -k2)

dc1,3.3529411764705882,12.4117647058823529,13.7647058823529412
dc2,2.9375,1,1.4375
dc2,20.875,20.625,41.5

обратите внимание, что есть два совпадения для DC2.

Бонус: для обязательного форматирования канала выводим предыдущий скрипт в

$ ... | tr ',' ' ' | xargs printf "%s,%.2f,%.2f,%.2f\n"
dc1,3.35,12.41,13.76
dc2,2.94,1.00,1.44
dc2,20.88,20.62,41.50

но тогда, возможно awk это лучшая альтернатива. Это показывает, что программирование не требуется, если вы можете использовать существующий набор инструментов Unix.

1

Вот решение с PHP:

foreach (file("dataset1.csv") as $line_no => $csv) {
if (!$line_no) continue; // in case you have a header on first line
$fields = str_getcsv($csv);
$key = array_shift($fields);
$data1[$key] = array_map(function ($v) { return number_format($v, 2); }, $fields);
};

foreach (file("dataset2.csv") as $csv) {
$fields = str_getcsv($csv);
if (!isset($data1[$fields[1]])) continue;
$data2[$fields[0]] = array_merge(array($fields[0]), $data1[$fields[1]]);
};

ksort($data2);

$csv = implode("\n", array_map(function ($v) {
return implode(',', $v);
}, $data2));

file_put_contents("dataset3.csv", $csv);

NB: Как вы упомянули, первый файл будет используя столбец 1 в качестве первичного ключа, двойное значение ключа не должно возникать. Если это произойдет, последний случай будет преобладать.

0