在 csv 中查找重复项和重复项的唯一性

Posted

技术标签:

【中文标题】在 csv 中查找重复项和重复项的唯一性【英文标题】:Finding duplicates, and uniques of the duplicates in a csv 【发布时间】:2020-03-28 13:28:49 【问题描述】:

我需要创建一个脚本,它将一个 csv(有时标记为 .inf)加载到内存中,并评估数据的一种重复类型。 csv 本身在每个字段中总是有不同的信息,但列将是相同的。大约 100~ 列。在我的示例中,为了便于阅读,我将其缩小到 10 列。

我正在寻找的副本的“类型”有点奇怪。我需要首先在第 2 列中找到所有重复项。然后我需要查看该组重复项,然后查看第 8 列(在我的实际 csv 中,它将是第 84 列)。 查看第 8 列,我只需要输出以下数据:

A.在第 2 列中重复

B.在第 8 列中唯一

第 2 列可能只有 2 个重复项,它们的第 8 列相同。我不需要看到那个。如果第 2 列有 3 个重复项,并且它们的第 8、2 列相同,并且 1 是唯一的,我需要查看所有 3 FULL 行。

Desired input
m,123veh,john;doe,10/1/2019,ryzen,split,32929,38757ace,turn,left
m,123veh,john;doe,10/1/2019,ryzen,split,32929,495842,turn,left
m,837iec,john;doe,10/1/2019,ryzen,split,32929,12345,turn,left
m,837iec,john;doe,10/1/2019,ryzen,split,32929,12345,turn,left
m,382ork,john;doe,10/1/2019,ryzen,split,32929,38757,turn,left
m,382ork,john;doe,10/1/2019,ryzen,split,32929,38757,turn,left
m,382ork,john;doe,10/1/2019,ryzen,split,32929,4978d87,turn,left

这些数据会不断变化,甚至第 8 列的字符数也可能不同。

Desired output
m,123veh,john;doe,10/1/2019,ryzen,split,32929,38757ace,turn,left
m,123veh,john;doe,10/1/2019,ryzen,split,32929,495842,turn,left
m,382ork,john;doe,10/1/2019,ryzen,split,32929,38757,turn,left
m,382ork,john;doe,10/1/2019,ryzen,split,32929,38757,turn,left
m,382ork,john;doe,10/1/2019,ryzen,split,32929,4978d87,turn,left 

您可以从我想要的输出中看到,我不需要查看带有 837iec 的行,因为虽然它们的第 2 列是重复的,但第 8 列相互匹配。我不需要看到那个。而对于像 382ork 这样的东西,8 列中有 2 个匹配,一个是唯一的。我需要看到所有 3 个。

我将在 unix 系统上使用它,我希望使用它的方式是键入“./scriptname filename.csv”,输出可以是标准输出,也可以是日志文件(如果需要)。

我无法找到一种方法来做到这一点,因为我需要如何比较第 8 列让我感到困惑。任何帮助将不胜感激。

我在另一个线程中发现了这个,它至少让我得到了完整的行,第 2 列的重复项。我以为我不完全理解它是如何工作的。

#!/usr/bin/awk -f

    lines[$1][NR] = $0;

END 
    for (vehid in lines) 
        if (length(lines[vehid]) > 1) 
            for (lineno in lines[vehid]) 
                # Print duplicate line for decision purposes
                print lines[vehid][lineno];
                # Alternative: print line number and line
                #print lineno, lines[vehid][lineno];
            
        
    

我的问题是它没有考虑下一列。它也不能很好地处理空白列。我的 csv 将有 100~ 列,其中 50~ 可能是完全空白的。

【问题讨论】:

当您说“完全空白”时,您的意思是它们将是“空的”?喜欢data1,data2,,,,,data8,....(我希望?)祝你好运。 是的,对不起。空是正确的,就像你那里的例子一样。 顺便说一句,你改进后的 Q 表现出色,你马上就能“关注”你的问题!祝你好运。 如果您刚刚进入这种处理并希望做更多的事情(并对您的数据源有一些控制),请考虑切换到制表符分隔的数据或@987654325 @ 分隔符。当您确实需要在数据中使用逗号时,使用未(或不能)出现在数据中的字符可以消除一整类问题;-)。祝你好运! @shellter,第一个问题确实非常好 T_Wrong,继续加油,干杯。 【参考方案1】:

请您尝试关注一下。

awk '
BEGIN
  FS=","

FNR==NR
  a[$2]++
  b[$2,$8]++
  c[$2]=(c[$2]?c[$2] ORS:"")$0
  next

a[$2]>1 && b[$2,$8]==1
  print c[$2]
  delete a[$2]
' <(sort -t',' -k2 Input_file) <(sort -t',' -k2 Input_file)

您显示的示例输出如下。

m,123veh,john;doe,10/1/2019,ryzen,split,32929,38757ace,turn,left
m,123veh,john;doe,10/1/2019,ryzen,split,32929,495842,turn,left
m,382ork,john;doe,10/1/2019,ryzen,split,32929,38757,turn,left
m,382ork,john;doe,10/1/2019,ryzen,split,32929,38757,turn,left
m,382ork,john;doe,10/1/2019,ryzen,split,32929,4978d87,turn,left

说明:为上述代码添加详细说明。

awk '                                                     ##Starting awk program from here.
BEGIN                                                    ##Starting BEGIN section from here.
  FS=","                                                  ##Setting FS as comma here.
                                                         ##Closing BEGIN section here.
FNR==NR                                                  ##Checking condition FNR==NR which will be TRUE when first time Input_file is being read.
  a[$2]++                                                 ##Creating an array named a whose index is $2 and increment its value with 1 each time it comes here.
  b[$2,$8]++                                              ##Creating an array named b whose index is $2,$8 and increment its value with 1 each time it comes here.
  c[$2]=(c[$2]?c[$2] ORS:"")$0                            ##Creating an array named c whose index is $2 and value will be keep concatenating its same indexs whole line value.
  next                                                    ##next will skip all further statements from here.
                                                         ##Closing BLOCK for FNR==NR condition here.
a[$2]>1 && b[$2,$8]==1                                   ##Checking condition if array a with index $2 value is greater than 1 AND array b with index $2,$8 value is 1.
  print c[$2]                                             ##Then print array c value with $2 here.
  delete a[$2]                                            ##Deleting array a value with $2 here which will make sure NO DUPLICATE lines are getting printed.
' <(sort -t',' -k2 file) <(sort -t',' -k2 file)          ##Sending Input_files in sorted format from 2nd field to make sure all values are coming together before doing operations on it.

【讨论】:

这看起来像它在做的伎俩!太感谢了!我已经为此苦苦挣扎了一段时间。 @T_Wrong,很高兴它对您有所帮助,欢迎您。我还添加了详细的解释(花了一些时间来添加详细的解释:))欢迎任何询问,干杯。 详细的解释很有帮助,谢谢。【参考方案2】:

这个问题的 Python 解决方案可能是(这里我使用 _idqty 来表示 2 个捕获的字段):

import csv
from collections import defaultdict

f = open('f1.txt', 'r')
d = defaultdict(lambda: defaultdict(list))

csv_reader = csv.reader(f)

for row in csv_reader:
    _id = row[1]
    qty = row[7]
    d[_id][qty].append(row)

f.close()

for _id in d:
    for qty in d[_id]:
        # if there are more than 1 'qty'
        # OR there is only 1 'qty' and there is only 1 line in the values
        # for the array (row) (allows a record with only 1 line)
        if len(d[_id]) > 1 or len(d[_id][qty]) == 1:
            for row in d[_id][qty]:
                print(','.join(row))

打印:

m,123veh,john;doe,10/1/2019,ryzen,split,32929,38757ace,turn,left
m,123veh,john;doe,10/1/2019,ryzen,split,32929,495842,turn,left
m,382ork,john;doe,10/1/2019,ryzen,split,32929,38757,turn,left
m,382ork,john;doe,10/1/2019,ryzen,split,32929,38757,turn,left
m,382ork,john;doe,10/1/2019,ryzen,split,32929,4978d87,turn,left

【讨论】:

谢谢!我一直在探索更多 Python,所以这很有帮助。【参考方案3】:

你可以用 pandas 来做这个,如果你可以使用的话:

import pandas as pd
e = pd.read_csv('out16.txt', header=None)
e.columns = list(range(1,11))
e.drop_duplicates(subset=[2,8]).set_index(1).to_csv('out_test.txt', header=False) 
e = e.drop_duplicates(subset=[2,8]).set_index(1)
e

输出:

       2         3          4      5      6      7        8     9     10
1        
m  123veh  john;doe  10/1/2019  ryzen  split  32929  38757ace turn  left                                                               
m  123veh  john;doe  10/1/2019  ryzen  split  32929   495842  turn  left
m  837iec  john;doe  10/1/2019  ryzen  split  32929    12345  turn  left
m  382ork  john;doe  10/1/2019  ryzen  split  32929    38757  turn  left
m  382ork  john;doe  10/1/2019  ryzen  split  32929  4978d87  turn  left

【讨论】:

这是我第一次听说熊猫,但我一定会去研究它! @T_Wrong Pandas 很棒,绝对推荐!

以上是关于在 csv 中查找重复项和重复项的唯一性的主要内容,如果未能解决你的问题,请参考以下文章

如何从包含 JavaScript 中重复项的数组中获取唯一值数组? [复制]

Excel中哪个函数可以统一去重复值后的唯一值的个数呢?

熊猫列的 To_CSV 唯一值[重复]

在PHP中查找数组元素的所有可能的唯一组合[重复]

Excel神奇的去重复值函数--UNIQUE函数

如何在 PySpark 中进行分组并查找列的唯一项目 [重复]