-
Notifications
You must be signed in to change notification settings - Fork 7
Update politeness v2 #367
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update politeness v2 #367
Changes from 5 commits
c3b4422
b388a32
14dc294
125d821
a6e99a7
183d1e6
bafe275
40aee79
8e15934
a011781
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -58,4 +58,5 @@ node_modules/ | |
| # testing | ||
| /output | ||
| /vector_data | ||
| test.py | ||
| test.py | ||
| test.ipynb | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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'}, | ||
| '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 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) 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): | ||
|
|
||
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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_followersfrom the other auxiliaries, so I refactored this so that we only use a consistent set of auxiliaries