Сравнивая содержимое двух файлов CSV, где отношение между этими двумя файлами указано в третьем файле? - PullRequest
0 голосов
/ 11 июня 2019

У меня есть два файла с данными о продажах, и я хочу проверить, совпадают ли номера продаж в первом файле с номерами продаж во втором файле. Но идентификатор продукта, используемый в каждом файле, различен. У меня есть 3-й файл с соответствием между старым идентификатором продукта и новым идентификатором продукта.

Старый файл продаж

Product ID   Store ID  Week ID  Sales 
a               1       201801   5
a               2       201801   4
a               2       201802   3 
b               1       201801   3
b               2       201802   4
b               3       201801   2  
c               2       201802   2

Новый файл продаж

Product ID   Store ID  Week ID  Sales 
X               1       201801   5
X               2       201801   4
X               2       201802   3 
Y               1       201801   5
Y               2       201802   4
Y               3       201801   2  
Z               2       201802   2

И файл соответствия старого идентификатора продукта / нового идентификатора продукта:

Old Product ID     New Product ID 
      a                   X
      b                   Y
      c                   Z 

Я хочу запустить скрипт или команду, которая могла бы проверить, одинаковы ли продажи для каждой комбинации продукта / магазина / недели в обоих файлах. То есть: Если a и X обозначают один и тот же товар, то я хочу проверить, совпадают ли продажи для данного магазина и данной недели в обоих файлах. Обратите внимание, что не все продукты, присутствующие в старом файле продаж, обязательно присутствуют в новом файле продаж.

Вывод должен выглядеть так:

Product ID   Store ID   Week ID  Sales Diff
 X               1       201801      0
 X               2       201801      0
 X               2       201802      0 
 Y               1       201801      2
 Y               2       201802      0
 Y               3       201801      0  
 Z               2       201802      0

Я подумываю о том, чтобы либо собрать все 3 файла в кучу фреймов данных pandas, а затем объединить и выполнить проверку с использованием утилит слияния и различий pandas, либо перенести файлы в некоторые таблицы красного смещения и использовать SQL для проверки. Но оба кажутся излишними. Есть ли более простой способ сделать это, используя утилиты командной строки / bash?

Ответы [ 3 ]

2 голосов
/ 11 июня 2019

Я поклонник подхода "сделай это в SQL", в частности, sqlite:

#!/bin/sh

oldsales="$1"
newsales="$2"
junction="$3"

# Import into database. Do once and reuse if running repeated reports on the same data
if [ ! -f sales.db ]; then
    sqlite3 -batch sales.db <<EOF
CREATE TABLE old_sales(product_id TEXT, store_id INTEGER, week_id INTEGER, sales INTEGER
                     , PRIMARY KEY(product_id, store_id, week_id)) WITHOUT ROWID;
CREATE TABLE new_sales(product_id TEXT, store_id INTEGER, week_id INTEGER, sales INTEGER
                     , PRIMARY KEY(product_id, store_id, week_id)) WITHOUT ROWID;
CREATE TABLE mapping(old_id TEXT PRIMARY KEY, new_id TEXT) WITHOUT ROWID;
.mode csv
.separator \t
.import '|tail -n +2 "$oldsales"' old_sales
.import '|tail -n +2 "$newsales"' new_sales
.import '|tail -n +2 "$junction"' mapping
.quit
EOF
fi

# And query it
sqlite3 -batch sales.db <<EOF
.headers on
.mode list
.separator \t
SELECT n.product_id AS "Product ID", n.store_id AS "Store ID", n.week_id AS "Week ID"
     , n.sales - o.sales AS "Sales Diff"
FROM old_sales AS o
JOIN mapping AS m ON o.product_id = m.old_id
JOIN new_sales AS n ON m.new_id = n.product_id
                   AND o.store_id = n.store_id
                   AND o.week_id = n.week_id
ORDER BY "Product ID", "Store ID", "Week ID";
.quit
EOF

Это предполагает, что ваши файлы данных разделены вкладками, и выдает вывод с разделением табуляцией (легко изменитьпри желании).Он также кэширует данные в файле sales.db и повторно использует его, если он существует, поэтому вы можете запустить отчет несколько раз для одних и тех же данных и только заполнить базу данных в первый раз, для повышения эффективности.

$ ./report.sh old_sales.tsv new_sales.tsv product_mappings.tsv
Product ID  Store ID    Week ID Sales Diff
X   1   201801  0
X   2   201801  0
X   2   201802  0
Y   1   201801  2
Y   2   201802  0
Y   3   201801  0
Z   2   201802  0
2 голосов
/ 11 июня 2019

Вот предложение для вашего pandas подхода. Я назвал ваш старый фрейм данных old и ваш новый фрейм данных new:

Сначала мы используем ваш третий фрейм данных в качестве словаря для map старого Product ID's для нового:

product_id_dct = dict(zip(df3['Old Product ID'], df3['New Product ID']))
old['Product ID'] = old['Product ID'].map(product_id_dct)

print(old)
  Product ID  Store ID  Week ID  Sales
0          X         1   201801      5
1          X         2   201801      4
2          X         2   201802      3
3          Y         1   201801      3
4          Y         2   201802      4
5          Y         3   201801      2
6          Z         2   201802      2

Затем мы делаем left merge для столбцов, в которых вы хотите проверить изменения. Обратите внимание, что слияние слева даст нам все совпадения, а различия будут отображаться в NaN. В этом случае у нас нет:

new.merge(old, on=['Product ID', 'Store ID', 'Week ID', 'Sales'], 
          suffixes=['_new', '_old'], 
          how='left')

  Product ID  Store ID  Week ID  Sales
0          X         1   201801      5
1          X         2   201801      4
2          X         2   201802      3
3          Y         1   201801      3
4          Y         2   201802      4
5          Y         3   201801      2
6          Z         2   201802      2

Если мы оставим sales как key, мы сможем сравнивать проще из-за аргумента suffixes:

new.merge(old, on=['Product ID', 'Store ID', 'Week ID'], 
          suffixes=['_new', '_old'], 
          how='left')

  Product ID  Store ID  Week ID  Sales_new  Sales_old
0          X         1   201801          5          5
1          X         2   201801          4          4
2          X         2   201802          3          3
3          Y         1   201801          3          3
4          Y         2   201802          4          4
5          Y         3   201801          2          2
6          Z         2   201802          2          2
0 голосов
/ 11 июня 2019
$ cat tst.awk
BEGIN { OFS="\t" }
ARGIND==1 { map[$2] = $1; next }
ARGIND==2 { old[$1,$2,$3] = $4; next }
FNR==1 { gsub(/  +/,OFS); sub(/ *$/,"_Diff"); print; next }
{ print $1, $2, $3, $4 - old[map[$1],$2,$3] }

$ awk -f tst.awk map old new | column -s$'\t' -t
Product ID  Store ID  Week ID  Sales_Diff
X           1         201801   0
X           2         201801   0
X           2         201802   0
Y           1         201801   2
Y           2         201802   0
Y           3         201801   0
Z           2         201802   0

Вышеуказанное использует GNU awk для ARGIND. С другими awk просто добавьте строку FNR==1 { ARGIND++ } сразу после строки BEGIN.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...