Python для удаления дубликатов, используя только некоторые, а не все столбцы

У меня есть файл input.txt с разделителями табуляции, подобный этому

A    B    C
A    B    D
E    F    G
E    F    T
E    F    K

Они разделены табуляцией.

Я хочу удалить дубликаты только тогда, когда несколько строк имеют одинаковые 1-й и 2-й столбцы.

Итак, несмотря на то, что 1-я и 2-я строки в 3-м столбце различаются, они имеют одинаковые 1-й и 2-й столбцы, поэтому я хочу удалить «A B D», который появляется позже.

Итак, output.txt будет таким.

A    B    C
E    F    G

Если бы мне нужно было удалить дубликаты обычным способом, я просто превращаю списки в функцию «установить», и все готово.

Но теперь я пытаюсь удалить дубликаты, используя только «некоторые» столбцы.

Используя Excel, это так просто.

Данные -> Удалить дубликаты -> Выбрать столбцы

Используя MatLab, это тоже легко.

import input.txt -> Использовать «уникальную» функцию по отношению к 1-му и 2-му столбцам -> Удалить строки с номером «1»

Но, используя python, я не мог найти, как это сделать, потому что все, что я знал об удалении дубликатов, это использование «set» в python.

===========================

Это то, что я экспериментировал после ответа undefined_is_not_a_function.

Я не знаю, как перезаписать результат в output.txt и как изменить код, чтобы я мог указать столбцы, которые следует использовать для удаления дубликатов (например, 3 и 5).

import sys
input = sys.argv[1]

seen = set()
data = []
for line in input.splitlines():
    key = tuple(line.split(None, 2)[0])
    if key not in seen:
        data.append(line)
        seen.add(key)

person user3123767    schedule 30.07.2014    source источник
comment
Вы проверяете только последовательные строки? Допустим, у вас есть ABF на входе в качестве 6-й строки. Должен ли он быть удален?   -  person Lafexlos    schedule 30.07.2014
comment
@Lafexlos Да, это нужно удалить. Последовательно это или нет, если это дубликат, его следует рассматривать как дубликат.   -  person user3123767    schedule 30.07.2014


Ответы (5)


Для этого следует использовать itertools.groupby. Здесь я группирую данные на основе первых двух столбцов, а затем использую next() чтобы получить первый элемент из каждой группы.

>>> from itertools import groupby                                   
>>> s = '''A    B    C                                              
A    B    D
E    F    G
E    F    T
E    F    K'''
>>> for k, g in groupby(s.splitlines(), key=lambda x:x.split()[:2]):
    print next(g)
...     
A    B    C
E    F    G

Просто замените s.splitlines() файловым объектом, если ввод поступает из файла.


Обратите внимание, что приведенное выше решение будет работать только в том случае, если данные отсортированы по первым двум столбцам, если это не так, вам придется использовать здесь set.

>>> from operator import itemgetter
>>> ig = itemgetter(0, 1) #Pass any column number you want, note that indexing starts at 0
>>> s = '''A    B    C
A    B    D
E    F    G
E    F    T
E    F    K
A    B    F'''     
>>> seen = set()
>>> data = []
>>> for line in s.splitlines():
...     key = ig(line.split())
...     if key not in seen:
...         data.append(line)
...         seen.add(key)
...         
>>> data
['A    B    C', 'E    F    G']
person Ashwini Chaudhary    schedule 30.07.2014
comment
Вы можете остановиться на этом? - person Jasper; 30.07.2014
comment
@undefined_is_not_a_function Спасибо! Я отредактировал свой вопрос, чтобы задать вам вопрос. Входные данные не сортируются по первым двум столбцам. И я не уверен, как перезаписать результат в output.txt Наконец, как можно гибко изменить код, чтобы он удалял дубликаты, скажем, по 3-му и 5-му столбцу? - person user3123767; 30.07.2014
comment
@undefinedisnotafunction Спасибо. Не могли бы вы рассказать мне о каком-нибудь более простом (= как можно больше примеров с пошаговыми, построчными пояснениями) руководстве, чем официальное руководство? Я всегда находил официальное руководство слишком общим, с недостаточными примерами и пошаговыми объяснениями. На этот раз я снова попробовал несколько вещей в учебнике, но у меня не получилось. И многие другие неофициальные руководства иногда были проще, но не исчерпывающими. - person user3123767; 30.07.2014
comment
@undefinedisnotafunction На самом деле ничего не помогло .. Не могу найти ни одного учебника, который действительно помог бы мне сохранить данные в output.txt. Я очень хочу выучить python, но никакие учебники не помогают. Хуже того, ваш код показал мне, что индекс списка выходит за пределы допустимого диапазона. - person user3123767; 01.08.2014
comment
@user3123767 user3123767 Запись в файл — это очень простая вещь, вы можете опубликовать новый вопрос, если столкнулись с какой-то конкретной проблемой. - person Ashwini Chaudhary; 01.08.2014
comment
@undefinedisnotafunction Я пробовал методы, использующие кодек, те, которые используют with, те, которые используют file.write(data), и все они не помогли. Я мог довольно легко выучить MatLab. Онлайн-учебник был фантастическим, и серия запросов в Google всегда очень помогала. Но я пока не могу найти ни одного полезного учебника по Python. Знаете ли вы какой-нибудь учебник, который всесторонне обучает базовым вещам с большим количеством примеров? - person user3123767; 01.08.2014
comment
@undefinedisnotafunction И почему возникает ошибка индекса списка вне диапазона? - person user3123767; 01.08.2014
comment
@user3123767 user3123767 Может быть, потому что в некоторых строках недостаточно столбцов. Например, если вы передаете ig(3, 4), а строка содержит только четыре столбца, вы получите IndexError. (Также не забывайте, что индексация начинается с 0 в Python) - person Ashwini Chaudhary; 01.08.2014
comment
@undefinedisnotafunction Я сделал ig = itemgetter(0, 1) и получил ошибку индекса. Я проверил файл, и он не пуст в 1-м и 2-м столбцах. - person user3123767; 01.08.2014
comment
@undefinedisnotafunction Я разместил новый вопрос по адресу stackoverflow.com/questions/25079516/ - person user3123767; 01.08.2014

если у вас есть доступ к системе Unix, sort — это хорошая утилита, созданная для решения вашей проблемы.

sort -u -t$'\t' --key=1,2 filein.txt

Я знаю, что это вопрос о Python, но иногда Python не подходит для этой задачи. И вы всегда можете встроить системный вызов в свой скрипт Python.

person toine    schedule 30.07.2014

из приведенного ниже кода вы можете это сделать.

file_ = open('yourfile.txt')
lst = []
for each_line in file_ .read().split('\n'):
    li = each_line .split()
    lst.append(li)
dic = {}
for l in lst:
    if (l[0], l[1]) not in dic:
        dic[(l[0], l[1])] = l[2]

print dic

извините за имена переменных.

person Selva    schedule 30.07.2014

Предполагая, что вы уже прочитали свой объект и у вас есть массив с именем rows (скажите мне, нужна ли вам помощь с этим), следующий код должен работать:

entries = set()
keys = set()
for row in rows:
   key = (row[0], row[1]) # Only the first two columns

   if key not in keys:
      keys.add(key)
      entries.add((row[0], row[1], row[2]))
person ex0ns    schedule 30.07.2014

пожалуйста, обратите внимание, что я не эксперт, но у меня все еще есть идеи, которые могут вам помочь.

Существует модуль csv, полезный для файлов csv, вы можете посмотреть его, если найдете что-то интересное.

Сначала я хотел бы спросить, как вы храните эти данные? В списке?

что-то вроде

[[A,B,C],
[A,B,D],
[E,F,G],...]

Может подойти. (возможно не лучший выбор)

Во-вторых, можно ли пройтись по всему списку?

Вы можете просто сохранить строку, сравнить ее со всеми строками.

Я бы сделал так: предположим, что список содержит буквы.

copy = list
index_list = []
for i in range(0, len(list)-1):
    for j in range(0, len(list)-1): #and exclude i of course
     if copy[i][1] == list[j][1] and copy[i][0] == list[j][0] and i!=j:
          index_list.append(j)
for i in index_list: #just loop over the index list and remove
list.pop(index_list[i])

это не рабочий код, но он дает вам идею. Это самая простая идея для выполнения вашей задачи, и вряд ли самая подходящая. (и это займет некоторое время, так как вам нужно выполнить квадратичное количество операций). Редактировать: поп; не удалять

person Paul    schedule 30.07.2014