【发布时间】:2021-05-26 09:31:15
【问题描述】:
我有大量的单词“组”。如果一组中的任何单词同时出现在 A 列和 B 列中,我想从两列中删除该组中的单词。如何循环遍历所有组(即遍历列表中的子列表)?
下面有缺陷的代码只删除了最后一组中的常用词,而不是全部三个组(列表)。 [如果组中的一个单词在字符串中,我首先创建一个指示符,然后如果两个字符串都包含该组中的一个单词,则创建另一个指示符。仅对于 A 和 B 对,其中都具有组中的单词,我删除了特定的组单词。]
如何正确指定循环?
编辑: 在我建议的代码中,每个循环都使用原始列重新开始,而不是循环遍历从前一组中删除的单词的列。
解决方案建议更加优雅和整洁,但如果它们是另一个单词的一部分,则删除这些单词(例如,单词 'foo' 正确地从 'foo hello' 中删除,但也错误地从 'foobar' 中删除。
# Input data:
data = {'A': ['summer time third grey abc', 'yellow sky hello table', 'fourth autumnwind'],
'B': ['defg autumn times fourth table', 'not red skies second garnet', 'first blue chair winter']
}
df = pd.DataFrame (data, columns = ['A', 'B'])
A B
0 summer time third grey abc defg autumn times fourth table
1 yellow sky hello table not red skies second garnet
2 fourth autumnwind first blue chair winter
# Groups of words to be removed:
colors = ['red skies', 'red sky', 'yellow sky', 'yellow skies', 'red', 'blue', 'black', 'yellow', 'green', 'grey']
seasons = ['summer times', 'summer time', 'autumn times', 'autumn time', 'spring', 'summer', 'winter', 'autumn']
numbers = ['first', 'second', 'third', 'fourth']
stuff = [colors, seasons, numbers]
# Code below only removes the last list in stuff (numbers):
def fA(S,y):
for word in listed:
if re.search(r'\b' + re.escape(word) + r'\b', S):
y = 1
return y
def fB(T,y):
for word in listed:
if re.search(r'\b' + re.escape(word) + r'\b', T):
y = 1
return y
def fARemove(S):
for word in listed:
if re.search(r'\b' + re.escape(word) + r'\b', S):
S=re.sub(r'\b{}\b'.format(re.escape(word)), ' ', S)
return S
def fBRemove(T):
for word in listed:
if re.search(r'\b' + re.escape(word) + r'\b', T):
T=re.sub(r'\b{}\b'.format(re.escape(word)), ' ', T)
return T
for listed in stuff:
df['A_Ind'] = 0
df['B_Ind'] = 0
df['A_Ind'] = df.apply(lambda x: fA(x.A, x.A_Ind), axis=1)
df['B_Ind'] = df.apply(lambda x: fB(x.B, x.B_Ind), axis=1)
df['inboth'] = 0
df.loc[((df.A_Ind == 1) & (df.B_Ind == 1)), 'inboth'] = 1
df['A_new'] = df['A']
df['B_new'] = df['B']
df.loc[df.inboth == 1, 'A_new'] = df.apply(lambda x: fARemove(x.A), axis=1)
df.loc[df.inboth == 1, 'B_new'] = df.apply(lambda x: fBRemove(x.B), axis=1)
del df['inboth']
del df['A_Ind']
del df['B_Ind']
df['A_new'] = df['A_new'].str.replace('\s{2,}', ' ')
df['A_new'] = df['A_new'].str.strip()
df['B_new'] = df['B_new'].str.replace('\s{2,}', ' ')
df['B_new'] = df['B_new'].str.strip()
预期输出是:
A_new B_new
0 grey abc defg table
1 hello table no second garnet
2 autumnwind blue chair winter
【问题讨论】:
-
我想您想说“如果任何组中的任何单词出现在 A 列或 B 列中”,因为按照您当前的措辞,您的预期输出是错误的。 “夏天”仅出现在 A 列中,但您仍将其删除...
-
老实说,我会做类似的事情,但使用列表推导。
[word for word in x if word not in flatten([l for l in stuff if (len([e for e in l if e in x.A]) > 0 and len([e for e in l if e in x.B]) >0)])]其中 flatten 是一个简单的 flatten 运算符。 -
不,预期的输出是正确的。在第一行中,A(夏季第三灰色 abc)和 B(defg 秋季第四表)中都有季节组的单词。因此,由于 A 和 B 中都有季节词,因此应从 A 中删除“summer”,从 B 中删除“autumn”。同理,应从 A 和 B 中删除数字词“third”和“fourth”第一行。这与第三行相比,其中“蓝色”没有从 B 中删除,因为 A 列中没有颜色字。
-
这也是我认为扁平化列表行不通的原因。使用 flatten 会删除所有地方的所有单词。相反,只有当同一组中的单词出现在 A 和 B 的同一行中时,我才需要删除一组中的单词。
-
我可以假设您的单词是由单个空格分隔的吗?使用字符串函数会比使用 re 容易得多