#python #pandas #duplicates
Вопрос:
Я использую следующие функции для удаления дубликатов при сохранении первого вхождения и без изменения порядка.
def uniqueList(row):
words = str(row).split(" ")
unique = words[0]
for w in words:
if w.lower() not in unique.lower():
unique = unique " " w
return unique
df["value_corrected"] = df["value_corrected"].apply(uniqueList)
""" 1 """
sentences = df["value_corrected"] .to_list()
for s in sentences:
s_split = s.split(' ') # keep original sentence split by ' '
s_split_without_comma = [i.strip(',') for i in s_split]
# method 1: re
compare_words = re.split(' |-', s)
# method 2: itertools
compare_words = list(itertools.chain.from_iterable([i.split('-') for i in s_split]))
# method 3: DIY
compare_words = []
for i in s_split:
compare_words = i.split('-')
# strip ','
compare_words_without_comma = [i.strip(',') for i in compare_words]
# start to compare
need_removed_index = []
for word in compare_words_without_comma:
matched_indexes = []
for idx, w in enumerate(s_split_without_comma):
if word.lower() in w.lower().split('-'):
matched_indexes.append(idx)
if len(matched_indexes) > 1: # has_duplicates
need_removed_index = matched_indexes[1:]
need_removed_index = list(set(need_removed_index))
# keep remain and join with ' '
print(" ".join([i for idx, i in enumerate(s_split) if idx not in need_removed_index]))
# print(sentences)
print(sentences)
В большинстве случаев это работает, за исключением:
- удаляет предлоги также, поскольку он применяется ко всему содержимому строки, я считаю, что для применения функции к словам с len >3 необходимо условие
- иногда удаляет «‘ «
- не устраняет дублирование, когда слово также находится в нижнем и верхнем углу, например: «apple» против «APPLE»
Образец данных:
data = {'Name': ["LOVABLE Lovable Period Panties Slip da Ciclo Mestruale Flusso Medio (Pacco da 2) Donna', 'Laessig LÄSSIG Set di Cucchiaio per bambini 4 pezzi Uni menta/mirtillo",
"Béaba BÉABA, Set di 6 Contenitori per la Pappa per Svezzamento Bebè in Silicone",
"L´Occitane L'OCCITANE - CREMA MANI NUTRIENTE AL BURRO DI KARITÈ PER PELLI SECCHE 150ML"]}
df = pd.DataFrame(data)
Желаемый результат:
LOVABLE Period Panties Slip da Ciclo Mestruale Flusso Medio (Pacco da 2) Donna
Laessig Set di Cucchiaio per bambini 4 pezzi Uni menta/mirtillo
Béaba, Set di 6 Contenitori per la Pappa per Svezzamento Bebè in Silicone
L´Occitane - CREMA MANI NUTRIENTE AL BURRO DI KARITÈ PER PELLI SECCHE 150ML
Есть ли способ, которым я могу изменить вышеуказанные функции, чтобы охватить и эти ситуации?
Огромное спасибо.
Комментарии:
1. В pandas вас интересует метод
DataFrame.duplicated()
, который вернет логическую последовательность, помечающую повторяющиеся строки, за исключением первого появления (это значение можно изменить сkeep
помощью параметра). Смотрите более подробную информацию здесь: pandas.pydata.org/docs/reference/api/…2. @Erlinska, спасибо, но если я правильно понял ваш ответ, я стараюсь удалять дубликаты в каждой строке, а не дублировать строки
3. Не могли бы вы привести пример входного кадра данных и ожидаемого результата?
4. Как и выше. Я думаю, что было бы лучше добавить к вопросу эти 10-15 предложений/строк (в разных сценариях). Мне нужно вывести их как <показать ожидаемое форматирование>.
5. @MDR, обновлено, спасибо
Ответ №1:
На основе предоставленных строк…
Попробуй:
import pandas as pd
import re
# import unidecode
data = {'Name': ["LOVABLE Lovable Period Panties Slip da Ciclo Mestruale Flusso Medio (Pacco da 2) Donna",
"Laessig LÄSSIG Set di Cucchiaio per bambini 4 pezzi Uni menta/mirtillo",
"Béaba BÉABA, Set di 6 Contenitori per la Pappa per Svezzamento Bebè in Silicone",
"L´Occitane L'OCCITANE - CREMA MANI NUTRIENTE AL BURRO DI KARITÈ PER PELLI SECCHE 150ML"]}
df = pd.DataFrame(data)
def dedupString(s):
'''
Given a string 's' it processes the string and returns a string with duplicated words removed.
- replaces acute accent with single quote
- split string inc. punctuation to list
- sets 'ALL CAPS' words to 'All Caps' words (only during processing)
- loops through list and removes duplicates
- if word has a uppercase in the third char (like L'Oréal) reinstates that
- deduplicates the list and returns the list joined with a " "
'''
#replace acute accent (´) with a single quote (')
s = s.replace("´", "'")
#split the string inc. punctuation. If ticks and dashes etc. go missing from the output
#add them to the end of the second square brackets below. Example -> [.,!?;-HERE]
l = re.findall(r"[w'] |[.,!?;-]", s)
output = []
seen = set()
#loop through the words
for word in l:
wordAllCaps = False
#if word is all caps record it
if word.isupper():
wordAllCaps = True
#change, for example 'THE' to 'The' (and 'The' to 'The' but hey)
if word[0].isupper():
word = word.capitalize()
#if the word is more than 3 chars
if len(word) > 3:
#and if the word as a single quote as the second char
if word[1] == "'":
#capitialize the third char in the word so "L'oréal" becomes "L'Oréal"
word = ''.join([word[:2], word[2].upper(), word[2 1:]])
#if the current word hasn't been seen before
if word not in seen:
#add it to seen
seen.add(word)
#if the word was originally all caps (like 'FOOBAR' but currently 'Foobar') change it back
if wordAllCaps:
word = word.upper()
#add word to the output string
output.append(word)
#return the list of words joined with spaces
return ' '.join(output)
df['Name2'] = df['Name']
# df['Name2'] = df['Name2'].apply(unidecode.unidecode)
df['Name2'] = df.apply(lambda x: dedupString(x['Name2']), axis=1)
df['Name2'] = df['Name2'].str.replace(' , ', ', ', regex=False)
print(df)
Выходы:
Name
0 LOVABLE Lovable Period Panties Slip da Ciclo M...
1 Laessig LÄSSIG Set di Cucchiaio per bambini 4 ...
2 Béaba BÉABA, Set di 6 Contenitori per la Pappa...
3 L´Occitane L'OCCITANE - CREMA MANI NUTRIENTE A...
Name2
0 LOVABLE Period Panties Slip da Ciclo Mestruale...
1 Laessig LÄSSIG Set di Cucchiaio per bambini 4 ...
2 Béaba, Set di 6 Contenitori per la Pappa Svezz...
3 L'Occitane - CREMA MANI NUTRIENTE AL BURRO DI ...
Примечание:
LOVABLE Lovable
становитсяLOVABLE
так, как сохраняется первое слово. АналогичноBéaba BÉABA,
становитсяBéaba,
, когда знак препинания перемещается, чтобы присоединиться к исходному первому слову.- Если вы рады перезаписать существующий столбец, измените
df['Name2'] =
его наdf['Name'] =
в приведенном выше коде. Я рекомендую проверить/ выбрать выходные данные перед удалением исходного столбца строк. - Я прокомментировал пару строк (3 и 59), которые могли бы удалить unicode (непроверенный). Я пока оставил это в стороне, но если потребуется, оно там есть. При проверке большего набора данных вы можете увидеть, вызывают ли символы юникода проблему (например,
façade Facade
вопрос в том, соответствует ли строка как дубликат или нет. Либо замените юникод перед удалением дубликатов (раскомментируйте строки 3 и 59 и попробуйте), либо оставьте как есть.
Это работает для заданных строк. Обратите внимание на комментарий в коде, если символы исчезают (по мере роста набора данных вам может потребоваться изменить регулярное выражение)…
#split the strings inc. punctuation. If ticks and dashes etc. go missing from the output
#add them to the end of the second square brackets below. Example -> [.,!?;-HERE]
l = re.findall(r"[w'] |[.,!?;-]", s)
Дополнительный:
Если ваш ожидаемый результат таков, что Laessig LÄSSIG
Laessig
вы попытаетесь:
import pandas as pd
import re
import unidecode
data = {'Name': ["LOVABLE Lovable Period Panties Slip da Ciclo Mestruale Flusso Medio (Pacco da 2) Donna",
"Laessig LÄSSIG Set di Cucchiaio per bambini 4 pezzi Uni menta/mirtillo",
"Béaba BÉABA, Set di 6 Contenitori per la Pappa per Svezzamento Bebè in Silicone",
"L´Occitane L'OCCITANE - CREMA MANI NUTRIENTE AL BURRO DI KARITÈ PER PELLI SECCHE 150ML"]}
df = pd.DataFrame(data)
swaps = {"ä":"ae",
#"ö":"oe",
"ü":"ue",
"Ä":"Ae",
#"Ö":"Oe",
"Ü":"Ue",
"ß":"ss"}
def toASCII(s):
'''
Input is a string;
- if the string contains any char in the keys of 'swaps' replace that char
- sets words that are ALL CAPS to All Caps for consistent output
'''
#if the string has a char that is in the keys of 'swaps'
if any(e in swaps.keys() for e in s):
#for each word
for w in s.split():
#if the word is ALL CAPS
if w.isupper():
#make it All Caps
s = s.replace(w, w.capitalize())
#replace, for example 'ä' with 'ae'
for w, l in swaps.items():
s = s.replace(w, l)
return s
def dedupString(s):
'''
Given a string 's' it processes the string and returns a string with duplicated words removed.
- replaces acute accent with single quote
- split string inc. punctuation to list
- sets 'ALL CAPS' words to 'All Caps' words (only during processing)
- loops through list and removes duplicates
- if word has a uppercase in the third char (like L'Oréal) reinstates that
- deduplicates the list and returns the list joined with a " "
'''
#replace acute accent (´) with a single quote (')
s = s.replace("´", "'")
#split the string inc. punctuation. If ticks and dashes etc. go missing from the output
#add them to the end of the second square brackets below. Example -> [.,!?;-HERE]
l = re.findall(r"[w'] |[.,!?;-]", s)
output = []
seen = set()
#loop through the words
for word in l:
wordAllCaps = False
#if word is all caps record it
if word.isupper():
wordAllCaps = True
#change, for example 'THE' to 'The' (and 'The' to 'The' but hey)
if word[0].isupper():
word = word.capitalize()
#if the word is more than 3 chars
if len(word) > 3:
#and if the word as a single quote as the second char
if word[1] == "'":
#capitialize the third char in the word so "L'oréal" becomes "L'Oréal"
word = ''.join([word[:2], word[2].upper(), word[2 1:]])
#if the current word hasn't been seen before
if word not in seen:
#add it to seen
seen.add(word)
#if the word was originally all caps (like 'FOOBAR' but currently 'Foobar') change it back
if wordAllCaps:
word = word.upper()
#add word to the output string
output.append(word)
#return the list of words joined with spaces
return ' '.join(output)
df['Name2'] = df['Name']
df['Name2'] = df.apply(lambda x: toASCII(x['Name2']), axis=1)
df['Name2'] = df['Name2'].apply(unidecode.unidecode)
df['Name2'] = df.apply(lambda x: dedupString(x['Name2']), axis=1)
df['Name2'] = df['Name2'].str.replace(' , ', ', ', regex=False)
print(df)
Выходы:
Name
0 LOVABLE Lovable Period Panties Slip da Ciclo M...
1 Laessig LÄSSIG Set di Cucchiaio per bambini 4 ...
2 Béaba BÉABA, Set di 6 Contenitori per la Pappa...
3 L´Occitane L'OCCITANE - CREMA MANI NUTRIENTE A...
Name2
0 LOVABLE Period Panties Slip da Ciclo Mestruale...
1 Laessig Set di Cucchiaio per bambini 4 pezzi U...
2 Beaba, Set di 6 Contenitori per la Pappa Svezz...
3 L'Occitane - CREMA MANI NUTRIENTE AL BURRO DI ...
Очевидно, что с большим набором данных вам придется посмотреть, довольны ли вы swaps
словарем. Я прокомментировал несколько вещей, потому что, например, вы можете не захотеть, чтобы такие слова Björn
(если они присутствуют в большем наборе) были преобразованы и т. Д.