Python 通过多列中的非唯一值比较两个csv文件,在匹配的位置输出到csv额外数据

Python 通过多列中的非唯一值比较两个csv文件,在匹配的位置输出到csv额外数据,python,csv,awk,Python,Csv,Awk,我的搜索词已经用完了,已经满了圈。我已经阅读并尝试了大量的问题和答案,我认为这将是一个相当简单的任务,但没有乐趣 我有两个csv文件 **file1.csv** (2,000 + lines)<br/> product_code, colour, size, sku, more cols..., barcode<br/> <span style="color: red"> item98, red, XL, adfd56384678, ..., null<

我的搜索词已经用完了,已经满了圈。我已经阅读并尝试了大量的问题和答案,我认为这将是一个相当简单的任务,但没有乐趣

我有两个csv文件

**file1.csv** (2,000 + lines)<br/>
product_code, colour, size, sku, more cols..., barcode<br/>
<span style="color: red">
item98, red, XL, adfd56384678, ..., null<br/>
item99, black, L, adfgk9087467, ..., null<br/>
item98, red, S, adfgad240568, ..., null<br/>
</span>

**file2.csv** (20,000 + lines)<br/>
ITEM_CODE, COLOUR, SIZE, BAR_CODE<br/>
<span style="color: red">
item98, RED, XL, 090900887<br/>
item98, RED, S, 43581034<br/>
item97, BLUE, M, 519685371<br/>
</span>
<pre>
awk -F',' -v OFS=, 'NR==FNR{a[$1,tolower($2),$3]=$4;next}{if( b = a[$1,tolower($2),$3]){ print $1,$2,$3,$4,b }}' file1.csv file2.csv > matched-result.csv
</pre>
**file1.csv**(2000多行)
产品代码、颜色、尺寸、sku、更多颜色、条形码
item98,红色,XL,adfd56384678,…,空值
条目99,黑色,L,adfgk9087467,…,空
项目98,红色,S,adfgad240568,…,空
**file2.csv**(20000多行)
项目编码、颜色、尺寸、条形码
项目98,红色,XL,090900887
第98项,红色,S,43581034
项目97,蓝色,M,519685371
我需要输出:

**matched-result.csv** (2,000 + lines)<br/>
product_code, colour, size, sku, more cols..., barcode<br/>
<span style="color: red">
item98, red, XL, adfd56384678, ..., 090900887<br/>
item99, black, L, adfgk9087467, ..., null<br/>
item98, red, S, adfgad240568, ..., 519685371<br/>
</span>
**匹配结果.csv**(2000多行)
产品代码、颜色、尺寸、sku、更多颜色、条形码
项目98,红色,XL,adfd56384678,…,090900887
条目99,黑色,L,adfgk9087467,…,空
项目98,红色,S,adfgad240568,…,519685371
sku和条形码是唯一的值,只能通过匹配产品代码、尺寸和颜色来识别。我需要在file1.csv末尾的新列中显示条形码。我第一次成功的ish尝试是使用awk


awk-F','-v OFS=,'NR==FNR{a[$1,tolower($2),$3]=$4;next}{if(b=a[$1,tolower($2),$3]){print$1,$2,$3,$4,}file1.csv file2.csv>matched-result.csv
我挣扎着输出整个file1.csv和结果,尝试打印$0,b,这创建了一个值为b的新行。我还希望所有的file1.csv输出为空,如果可能的话为非匹配项和头。我必须对齐列以匹配此awk方法,但原始字段不对齐。这没什么大不了的,但我想知道是否有必要,是否有工作要做

在那之后,我尝试使用python脚本将file1.csv与awk输出文件匹配的result.csv合并

awk -F", " 'FNR==NR{;a[$1,tolower($2),$3]=$NF;next} (($1,$2,$3) in a){$NF=a[$1,$2,$3]} 1' file2.csv file1.csv
导入csv 从集合导入订单 将open('file1.csv')作为f: r=csv.reader(f,分隔符=',') dict1={row[0]:r}中的行的行[1:] 将open('matched-result.csv')作为f: r=csv.reader(f,分隔符=',') dict2=ORDERDEDDICT((行[0],行[1:]),用于r中的行) 结果=OrderedDict() 对于d in(第1条、第2条): 对于键,d.iteritems()中的值: result.setdefault(键,[]).extend(值) 将open('desired-result.csv','wb')作为f: w=csv.writer(f) 对于键,result.iteritems()中的值: w、 writerow([键]+值) 输出不是期望的结果。顺序错误记录数与file1.csv不完全匹配有多余的一行吗?此外,这两步方法似乎脱节,感觉其中一步如果做得好就可以完成任务

我尝试了csvkit来加入/合并文件,但输出了20000多行,其中一些是重复的。我认为它将product\u code/ITEM\u code列视为唯一值,而不是唯一值。我已经调查过join和grep,但他们似乎也不是答案

我已经安装了panda和powerShell,并愿意试一试,但不知道从哪里开始,那里需要明确的说明。哦,我对所有这些语言和程序都很熟悉,但还没有完全听懂

希望我已经提供了足够的信息继续下去。我会在这里发布我读过的帖子的链接。你可以接受我的工作,因为它是他们的+90%

请提供回复、代码示例,最好不要使用全新的语言或方法。

//更新

我投票赞成这个答案,因为它或多或少地解决了框栏的一个小调整,见评论。但值得指出的是,awk方法同样适用于相同的结果。当/如果我听到反馈并更新此位时,我将采用熊猫方法

万一有人在乎,我认为哪种方法是最好的?托马托,托马托,我不确定这在印刷品中是否有效。就个人而言,python更容易阅读。Awk又好又短,我认为它是一种基于正则表达式的语言,我发现它更难理解,学习曲线也更陡峭


感谢所有发表评论的人。我为此绞尽脑汁了很长一段时间,很快就把它整理好了。

我认为您的输出中存在一些不一致的地方,如果我们考虑将$1、2和$3作为file2.csv文件的索引,理想情况下,您显示的输出的最后一行不应该在那里

如果是,这是一个打字错误,那么下面可能会帮助你在同样的问题上

awk -F", " '{gsub('/\r/',"")} FNR==NR{;a[$1,tolower($2),$3]=$NF;next} (($1,$2,$3) in a){$NF=a[$1,$2,$3]} 1' file2.csv file1.csv
编辑:由于OP在输入_文件中有控制M个字符,因此现在也向其添加以下内容

import csv

# load the second file in memory as we need it for a barcode lookup
barcodes = {}  # will hold a map for our barcode values
with open("file2.csv", "rU") as f:  # open file2.csv for reading
    reader = csv.reader(f)  # create a CSV reader, you may need to tweak its options
    next(reader)  # skip the header
    for row in reader:  # loop it row by row
        # store code:color:size map as a tuple in our barcodes map
        barcodes[(row[0], row[1].lower(), row[2])] = row[3]
# now you can get a barcode from it like: barcodes[("item98", "red", "XL")]

# open file1.csv for reading and matched-result.csv for writing
with open("file1.csv", "rU") as f, open("matched-result.csv", "w") as out:
    reader = csv.reader(f)  # create a CSV reader, you may need to tweak its options
    header = next(reader)  # get the header
    indexes = {column: index for index, column in enumerate(header)}  # map column indexes
    writer = csv.writer(out, lineterminator="\n")  # create a CSV writer for our output
    writer.writerow(header)  # write the same header to the output file
    for row in reader:  # loop through file1.csv rows
        # create a search map entry
        search = (row[indexes["product_code"]], row[indexes["colour"]], row[indexes["size"]])
        if search in barcodes:  # we have a barcode entry
            row[indexes["barcode"]] = barcodes[search]  # update it in the current row
        writer.writerow(row)  # write the potentially modified row to our output file

一种简单且通用的Python方法:

product_code,colour,size,sku,added_col,barcode item98,red,XL,adfd56384678,1,null item99,black,L,adfgk9087467,2,null item98,red,S,adfgad240568,3,null 如果
file2.csv
可能具有不同顺序的列,则必须确保映射部分(
barcodes[(行[0],行[1]。lower(),行[2])]=行[3]
)与列顺序tho匹配

编辑-因为我以前没有测试过它,所以我编写了一个简单的测试,看看它是否正常工作:

file1.csv

ITEM_CODE,COLOUR,SIZE,BAR_CODE item98,RED,XL,090900887 item98,RED,S,43581034 item97,BLUE,M,519685371 product_code,colour,size,sku,added_col,barcode item98,red,XL,adfd56384678,1,090900887 item99,black,L,adfgk9087467,2,null item98,red,S,adfgad240568,3,43581034 并生成
匹配结果.csv
包含:

import pandas as pd

df_sku = pd.read_csv('file1.csv', index_col=False)
df_bc = pd.read_csv('file2.csv', index_col=False)
res = df_sku.merge(df_bc, left_on=['product_code', 'colour', 'size'], right_on=['ITEM_CODE', 'COLOUR', 'SIZE'])
产品代码、颜色、尺寸、sku、添加颜色、条形码 项目98,红色,XL,adfd56384678,1090900887 项目99,黑色,L,adfgk9087467,2,空 项目98,红色,S,adfgad240568,343581034 如果您的CSV文件遵循问题中提出的结构,就像这些一样,它应该可以正常工作。我在您的数据中可能看到的唯一问题是,逗号后面有一个空格分隔值。如果您的数据确实如此,请将
skipinitialspace=True
添加到每个
csv.reader()
(例如
reader=csv.reader(f,skipinitialspace=True)
)的参数中,以说明额外的空间。正如我在代码中所写,您可能需要调整
csv.reader()/csv.writer()
import pandas as pd

df_sku = pd.read_csv('file1.csv', index_col=False)
df_bc = pd.read_csv('file2.csv', index_col=False)
res = df_sku.merge(df_bc, left_on=['product_code', 'colour', 'size'], right_on=['ITEM_CODE', 'COLOUR', 'SIZE'])