比较两个csv文件的内容,其中在第三个文件中指定了两个文件之间的关系?

时间:2019-06-10 21:10:56

标签: mysql bash pandas csv

我有两个包含销售数据的文件,并且我想验证第一个文件中的销售编号是否与第二个文件中的销售编号相同。但是每个文件中使用的产品ID是不同的。我确实有第三个文件,其中包含旧产品ID和新产品ID之间的对应关系。

旧销售文件

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

以及旧产品ID /新产品ID对应文件:

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合并和差异实用程序进行合并和验证,或者将文件拉入一些redshift表并使用SQL进行验证。但是两者似乎都不过分。有使用命令行/ bash实用程序执行此操作的更简单方法吗?

3 个答案:

答案 0 :(得分:2)

以下是您的pandas方法的建议。我叫你的旧数据框old和新的数据框new

首先,我们将您的第三个数据框用作字典,将旧的Product ID's map转换为新的{

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

答案 1 :(得分:2)

我是“在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 :(得分:0)

$ 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

以上对ARGIND使用GNU awk。对于其他awk,只需在FNR==1 { ARGIND++ }行之后添加BEGIN行。