合并两个 csv 文件,为所有匹配的记录添加一个带有标志值的列
Posted
技术标签:
【中文标题】合并两个 csv 文件,为所有匹配的记录添加一个带有标志值的列【英文标题】:Merge two csv files, add a column with a flag value for all matched records 【发布时间】:2021-09-19 03:59:38 【问题描述】:我有两个包含数据的 csv 文件,我想匹配它们,并在它们匹配时添加一个包含标志值的列。第一个文件是包含所有患者的“主”文件,第二个文件包含已签名的文档 ID。
文件 1 的内容:
recid visit docid
1 arm1 1012
2 arm1 1023
3 arm1 1024
4 arm1 1026
5 arm1 1028
6 arm1 1031
7 arm1 1037
8 arm1 1040
文件 2 的内容:
docid
1023
1024
1028
所需的输出文件:
recid visit docid match
1 arm1 1012
2 arm1 1023 1
3 arm1 1024 1
4 arm1 1026
5 arm1 1028 1
6 arm1 1031
7 arm1 1037
8 arm1 1040
这是我目前得到的代码:
import pandas as pd
# which file to read
IN_FILE1 = "patients.txt"
IN_FILE2 = "informedconsent.txt"
OUT_FILE = "output_matched.csv"
# load data from csv files
df_file1 = pd.read_csv (IN_FILE1, sep = "\t")
df_file2 = pd.read_csv (IN_FILE2, sep = "\t")
# merge on docid
df_merge = df_file1.merge(df_file2, on='docid', how='left')
# flag the matches
if df_merge['docid'].empty:
df_merge['matched'] = ""
else:
df_merge['matched'] = "1"
print(df_merge) #test
# write to file
df_merge.to_csv (OUT_FILE, sep = "\t", index = False, header=True)
问题显然是它被合并到docid
列上,所以它永远不会为空。但是第二个文件只包含一列,因此没有添加新列,否则我可以检查那些新列或其他内容。
如果我将其更改为how='inner'
,那么它可以工作,但我只能得到匹配项,但结果需要是第一个文件的所有记录,即使它们不匹配。
当我编辑 file2 并将列名更改为 docid2
并将代码更改为:
df_merge = df_file1.merge(df_file2, left_on='docid', right_on='docid2', how='left')
if df_merge['docid2'].empty:
# etc..
它添加了一个docid2
列,该列仅在匹配时包含一个 guid 值,所以这是正确的。但是matched
列仍然始终包含“1”。
关于如何做到这一点的任何想法?
【问题讨论】:
【参考方案1】:merge
带指示器:
df3 = df1.merge(df2, on='docid', how='left', indicator='match')
df3
:
recid visit docid match
0 1 arm1 1012 left_only
1 2 arm1 1023 both
2 3 arm1 1024 both
3 4 arm1 1026 left_only
4 5 arm1 1028 both
5 6 arm1 1031 left_only
6 7 arm1 1037 left_only
7 8 arm1 1040 left_only
然后map
进行数值转换:
df3['match'] = df3['match'].map('both': 1, 'left_only': '')
df3
:
recid visit docid match
0 1 arm1 1012
1 2 arm1 1023 1
2 3 arm1 1024 1
3 4 arm1 1026
4 5 arm1 1028 1
5 6 arm1 1031
6 7 arm1 1037
7 8 arm1 1040
或不带merge
通过np.where
和isin
:
df1['match'] = np.where(df1['docid'].isin(df2['docid']), 1, '')
df1
:
recid visit docid match
0 1 arm1 1012
1 2 arm1 1023 1
2 3 arm1 1024 1
3 4 arm1 1026
4 5 arm1 1028 1
5 6 arm1 1031
6 7 arm1 1037
7 8 arm1 1040
【讨论】:
感谢您的彻底回答,但最终方法给出错误“NameError:名称'np'未定义”,当我将np.
更改为df_file1.
时,我得到“For argument”就地" 预期类型 bool,接收类型 str。"
numpy
是pandas
的依赖库,您需要将其导入import numpy as np
,但如果安装了pandas,则numpy
也是如此【参考方案2】:
你可以使用.isin()
:
df_file1['match'] = (df_file1['docid'].isin(df_file2['docid'])*1).replace(0,'')
print(df_file1)
recid visit docid match
0 1 arm1 1012
1 2 arm1 1023 1
2 3 arm1 1024 1
3 4 arm1 1026
4 5 arm1 1028 1
5 6 arm1 1031
6 7 arm1 1037
7 8 arm1 1040
【讨论】:
感谢您的快速回答,有很多答案,我接受了另一个。.isin
听起来是正确的做法。
@BdR 非常欢迎您。我了解到您选择了多个.isin()
solutions 中的一个答案,请注意认为这个答案是最紧凑的,也是最早使用.isin 的答案。如果您因为可读性而选择另一个,我会理解的。编码愉快!【参考方案3】:
使用isin
+ astype
+ replace
df_parent['match'] = df_parent['docid'].isin(df_docid['docid']).astype(int).replace(0, '')
输出:
recid visit docid match
0 1 arm1 1012
1 2 arm1 1023 1
2 3 arm1 1024 1
3 4 arm1 1026
4 5 arm1 1028 1
5 6 arm1 1031
6 7 arm1 1037
7 8 arm1 1040
【讨论】:
感谢您的快速回答,.isin
正是我想要的。虽然我不认为我会弄清楚所需的类型转换。以上是关于合并两个 csv 文件,为所有匹配的记录添加一个带有标志值的列的主要内容,如果未能解决你的问题,请参考以下文章