I wrote a simple NN text classifier to help me quickly sort through the new daily submissions to the arXiv. It
- downloads the new submissions, processings their titles and abstracts,
- trains a NN on some manually-labeled data,
- uses the trained model to classify the new submissions, and
- presents the results allowing the user to either accept/reject/re-classify the submissions.
The implementation is pretty straightforward and can be found here: https://github.com/Gabriel-p/arXivNN. The two weaker spots I believe are:
- The soup parser which I'm sure could be done better
import re
from bs4 import BeautifulSoup as BS
import requests
categ = "astro-ph"
subcategs = ("astro-ph.GA", "astro-ph.IM")
url = "http://arxiv.org/list/" + categ + "/new"
html = requests.get(url)
soup = BS(html.content, features="xml")
# Store urls for later
dt_tags = soup.find_all('dt')
all_urls = [_.find_all('a')[1].get('id') for _ in dt_tags]
all_urls = ["https://arxiv.org/abs/" + _ for _ in all_urls]
# Extract titles and abstracts, only for the matching sub-categories
dd_tags = soup.find_all('dd')
articles = []
for i, dd_element in enumerate(dd_tags):
subjects = dd_element.find(class_='list-subjects').text
subcategs_new = extract_text_in_parentheses(subjects)
# Check if submission fits any sub-category
if any(element in subcategs_new for element in subcategs):
title = dd_element.find(class_='list-title mathjax').text
title = title.split('\n')[1].strip()
abstract = dd_element.find_all(class_='mathjax')[-1].text.strip()
articles.append([title, abstract, all_urls[i]])
def extract_text_in_parentheses(text):
pattern = r"\((.*?)\)"
matches = re.findall(pattern, text)
matches = [_.lower() for _ in matches]
return matches
- The NN itself for which I basically just followed Claude's instructions
preprocessed_texts = preprocess_text(texts)
# Convert to TF-IDF representation
vectorizer = TfidfVectorizer(max_features=max_features)
tfidf_matrix = vectorizer.fit_transform(preprocessed_texts)
X = tfidf_matrix.toarray()
# Convert labels to categorical
y = to_categorical(np.array(labels) - 1, num_classes=num_classes)
# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42)
# Build the neural network model
model = Sequential([
Input(shape=(max_features,)),
Dense(64, activation='relu'),
Dense(32, activation='relu'),
Dense(16, activation='relu'),
Dense(num_classes, activation='softmax')
])
# Compile the model
model.compile(
optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']
)
# Train the model
model.fit(
X_train, y_train, epochs=100, batch_size=32, validation_split=0.2, verbose=verb
)
# Evaluate the model
loss, accuracy = model.evaluate(X_test, y_test, verbose=verb)
print(f"Test accuracy: {accuracy:.4f}")
In my tests I get a ~0.7-0.75 accuracy which is not bad I believe, but maybe it can be improved?