Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,5 @@ node_modules/
# testing
/output
/vector_data
test.py
test.py
test.ipynb
57 changes: 53 additions & 4 deletions src/team_comm_tools/features/keywords.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# reference: https://github.com/bbevis/politenessPy/blob/main/keywords.py
kw = {
"spacy_neg_only": {
"Negative_Emotion": [
Expand Down Expand Up @@ -7260,7 +7261,34 @@
" sorry ",
" woops ",
" whoops ",
" oops "
" oops ",
" apology "
],
"Third_Person": [
" he ",
" him ",
" his ",
" himself ",
" she ",
" her ",
" hers ",
" herself ",
" they ",
" them ",
" their ",
" theirs ",
" themselves "
],
"Contrast_Conjunction": [
" but ",
" however ",
" instead ",
" although ",
" even though ",
" despite ",
" and yet ",
" nevertheless ",
" nonetheless "
],
"Ask_Agency": [
" do me a favor ",
Expand Down Expand Up @@ -7365,7 +7393,6 @@
"Gratitude": [
" thank ",
" thanks ",
" thank you ",
" grateful ",
" gratitude ",
" cheers "
Expand Down Expand Up @@ -14419,25 +14446,47 @@
" cock ",
" crap ",
" damn ",
" dammit ",
" damnit ",
" dick ",
" dickhead ",
" dick-head ",
" dumb ",
" dumbass ",
" dumb-ass ",
" dumb ass ",
" dyke ",
" fuck ",
" fucking ",
" fucker ",
" goddam ",
" goddammit ",
" goddamed ",
" hell ",
" horshit ",
" homo ",
" jackass ",
" jackass ",
" motherfucker ",
" mother-fucker ",
" motherfucking ",
" nigger ",
" nigra ",
" piss ",
" prick ",
" pussy ",
" queer ",
" screw ",
" shit ",
" shite ",
" shitting ",
" sob ",
" sonofa ",
" suck ",
" sucked ",
" sucks "
" sucks ",
" twat ",
" wanker ",
" whore "
],
"Truth_Intensifier": [
" really ",
Expand Down
86 changes: 68 additions & 18 deletions src/team_comm_tools/features/politeness_v2_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,29 +218,79 @@ def bare_command(doc):
def Question(doc):
"""
Counts the number of sentences containing question words and question marks.

Reference: https://github.com/bbevis/politenessPy/blob/main/strategy_extractor.py
Args:
doc (spacy.tokens.Doc): The spaCy Doc object containing the text to be analyzed.

Returns:
tuple: A tuple containing the counts of Yes/No questions and WH-questions.
"""

keywords = set([' who ', ' what ', ' where ', ' when ', ' why ', ' how ', ' which '])
tags = set(['WRB', 'WP', 'WDT'])

# doc = nlp(text)
sentences = [str(sent) for sent in doc.sents if '?' in str(sent)]
all_qs = len(sentences)

n = 0
for i in range(len(sentences)):
whq = [token.tag_ for token in nlp(sentences[i]) if token.tag_ in tags]

if len(whq) > 0:
n += 1

return all_qs - n, n
# POS tags for WH-words like who/what/where
search_tags = {'WRB', 'WP', 'WDT'}
# WH-words and common auxiliaries that follow them in real questions
wh_words = {'what', 'who', 'where', 'when', 'why', 'how', 'which'}
wh_followers = {
'what': {'are', 'is', 'do', 'does', 'can', 'should', 'might'},
'who': {'am', 'is', 'are', 'was', 'can', 'should'},

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sundy1994 I found a bug when testing this. It turns out that if you do not add 'am' to WH_followers, things like who am I or what am I supposed to do are not detected as WH_questions. But there are still some bugs with this... I'll follow up on Slack.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UPDATE - I realized that it actually doesn't make much sense to separate the wh_followers from the other auxiliaries, so I refactored this so that we only use a consistent set of auxiliaries

'where': {'is', 'are', 'can', 'should'},
'when': {'is', 'are', 'can', 'should'},
'why': {'is', 'are', 'do', 'does', 'can', 'might', 'would'},
'how': {'is', 'are', 'do', 'does', 'can', 'should', 'would'},
'which': {'is', 'are', 'was', 'can', 'should'}
}
# Auxiliaries that typically initiate Yes/No questions
yesno_aux = {
'do', 'does', 'did', 'have', 'has', 'had',
'can', 'could', 'will', 'would',
'may', 'might', 'shall', 'should',
'is', 'are', 'was', 'were', 'am'
}
# Pronouns that often follow auxiliaries in Yes/No questions
pronoun_followers = {'i', 'you', 'we', 'he', 'she', 'they', 'it'}

wh_count = 0
yesno_count = 0
counted_sentences = set()
for sent in doc.sents:
sent_text = sent.text.strip()
sent_tokens = list(sent)
if not sent_tokens:
continue
# Method 1: Find question sentences by checking for '?' at end

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So there's a bug with this logic, which is that, if the sentence doesn't end with a question mark, the fallback method is very error prone. For example:

Question(nlp("can you tell me what is your name?")) yields YesNo = 1, WH = 0 (correct)
Question(nlp("can you tell me what is your name")) yields YesNo = 0, WH = 1 (incorrect)

Why can't we use logic that looks for the question words, but then applies the logic with the search_tags, which helps to get around some of these problems?

if sent_text.endswith('?'):
# try to find the first WH-word in the sentence
wh = False
for token in sent_tokens:
if token.text.lower() in wh_words and token.tag_ in search_tags and token.dep_ not in {"relcl", "acl"}\
and token.i < sent.root.i:
wh = True
break
if wh:
wh_count += 1
else:
# Fallback: no WH in the sentence → treat as Yes/No question
yesno_count += 1
counted_sentences.add(sent.start)
continue
# Method 2: For remaining sentences, apply lexical rule-based detection --- Extract tokens and their metadata for fast access
for i in range(len(sent_tokens) - 1):
tok1 = sent_tokens[i]
tok2 = sent_tokens[i + 1]
t1_lower = tok1.text.lower()
t2_lower = tok2.text.lower()
if sent.start in counted_sentences:
break # already counted
# Yes/No pattern
if t1_lower in yesno_aux and t2_lower in pronoun_followers:
yesno_count += 1
counted_sentences.add(sent.start)
break
# WH pattern
if t1_lower in wh_words and tok1.tag_ in search_tags and tok1.dep_ not in {"relcl", "acl"}\
and tok1.i < sent.root.i and t2_lower in wh_followers.get(t1_lower, set()):
wh_count += 1
counted_sentences.add(sent.start)
break
return yesno_count, wh_count


def word_start(keywords, doc):
Expand Down
8 changes: 7 additions & 1 deletion tests/data/cleaned_data/test_chat_level.csv
Original file line number Diff line number Diff line change
Expand Up @@ -1437,11 +1437,17 @@ yeomans_test,yeomans_user_b,I guess they almost complete it.,Hedges_receptivenes
yeomans_test,yeomans_user_a,"Ma'am, no my lady, do you know Mr. Smith?",Formal_Title_receptiveness_yeomans,2
yeomans_test,yeomans_user_b,"I agree, this is correct",Agreement_receptiveness_yeomans,2
yeomans_test,yeomans_user_a,This is for you. Why you don't understand it's for you?,For_You_receptiveness_yeomans,2
yeomans_test,yeomans_user_b,"Thank you, I'm really grateful",Gratitude_receptiveness_yeomans,3
yeomans_test,yeomans_user_b,"Thank you, I'm really grateful",Gratitude_receptiveness_yeomans,2
yeomans_test,yeomans_user_a,We here you. We totally understand,Acknowledgement_receptiveness_yeomans,2
yeomans_test,yeomans_user_b,"Shit. You dumb asshole, what the hell? Who's that bastard? Suck my dick.",Swearing_receptiveness_yeomans,7
yeomans_test,yeomans_user_a,"Hey hello good morning, oh actually good evening.",Hello_receptiveness_yeomans,4
yeomans_test,yeomans_user_b,Are you sure? Is this the guy? Did he lie to you?,YesNo_Questions_receptiveness_yeomans,3
yeomans_test,yeomans_user_a,"Did you finish the report, which was due today?",YesNo_Questions_receptiveness_yeomans,1
yeomans_test,yeomans_user_b,"Did you finish the report, which was due today?",WH_Questions_receptiveness_yeomans,0
yeomans_test,yeomans_user_a,"We can start here. What is the question?",WH_Questions_receptiveness_yeomans,1
yeomans_test,yeomans_user_b,"Has she met the teacher who helped you last year?",WH_Questions_receptiveness_yeomans,0
yeomans_test,yeomans_user_a,"Do you know what time it is?",WH_Questions_receptiveness_yeomans,0
yeomans_test,yeomans_user_b,"Have you read the article that explains why this happens?",WH_Questions_receptiveness_yeomans,0
yeomans_test,yeomans_user_a,I'm sorry I sincerely apologize.,Apology_receptiveness_yeomans,2
yeomans_test,yeomans_user_b,Wow! Amazing! Perfect!,Affirmation_receptiveness_yeomans,3
yeomans_test,yeomans_user_a,I love you. My friend,First_Person_Single_receptiveness_yeomans,2
Expand Down