The problem in brief
Malay is written in two very different registers: bahasa baku, the standard language of newspapers and official texts, and bahasa pasar ("market language"), the relaxed, abbreviated, code-switched language of social media and product reviews. You get 820 labelled texts (class 0 = baku, classes 1 to 5 = various kinds of pasar) and 93 unlabelled test texts, and must label each test text 0 or 1. Predictions were posted to the Malaysian olympiad's API, so the official test labels are private: we estimate our score with repeated cross-validation on the training set, and use the data from the public mirror jaredliw/ioai-tsp-2025.
How you are scored
The server computes the F1 score of the pasar class (label 1), and the task is worth points:
The statement hints at a trap: predicting 0 everywhere gives , hence , even though it would be right about half the time. F1 ignores true negatives, so it only rewards finding the positive class.
There is no published threshold. The mirror notebook is a contestant's solution and reports its server scores: 8.94 (counts + logistic regression), 9.57 (TF-IDF + logistic regression) and 9.78, i.e. (TF-IDF + linear SGD classifier). We use that last number as the reference level.
First look at the data
- The classes are balanced once merged: 415 baku against 405 pasar (45, 90, 45, 90 and 135 texts in sub-classes 1 to 5).
- Every baku text looks like a news sentence: "Pasukan Polis Marin (PPM) Wilayah Satu Langkawi membongkar sindiket ... semalam." Capital letter, full sentence, final period, words like semalam (yesterday), lapor (reported), polis.
- Pasar texts are comments and reviews: abbreviations (yg for yang, tk for tak, dh, utk), particles (la, je, ni, tu), emojis, stretched letters ("jaaa", "BAGUSSS"), English mixed in ("Thank you seller"), and also Indonesian slang (ngga, bisa, banget).
So the task is easier than "judge the grammar": in this dataset the register is tied to the source (news vs social media), and both leave strong lexical fingerprints.
A first baseline
Two rules with no learning at all:
| rule | F1 (pasar) |
|---|---|
| predict everything pasar | 0.661 |
| baku if the text starts with a capital and ends with a period | 0.764 |
The punctuation rule already captures something real, but many casual comments are punctuated properly and some news snippets end with a quote. We need the words.
The key idea
A linear model on bag-of-words features is the right tool when the classes differ in vocabulary. Represent each text as a sparse vector of TF-IDF weights (term frequency times inverse document frequency, so that frequent-everywhere words count less), and learn a weight per feature:
Each weight says how much a token pushes toward pasar () or baku (). With 820 texts and thousands of features, a regularised linear model (logistic regression, linear SVM, Naive Bayes) is hard to beat: it has one parameter per word, which is exactly the amount of structure this data supports.

The learned weights (left panel) are a lesson in themselves:
- On the pasar side: yg (abbreviation of yang), tak, dah, nak, ni, tu, aku (informal "I"). These are exactly the markers a linguist would list.
- On the baku side: formal function words (di, pada, apabila, seorang, sebuah) but also news topics (polis, negeri, Malaysia, lapor) and semalam. with its period. The model has partly learned "is this a news article?", not only "is this standard Malay?". That works on this test set because it comes from the same sources, but a formal text about another topic (a sermon, a textbook) could fool it.
Character n-grams add robustness to spelling variation, which is the essence of pasar: "bagus", "bagusss" and "bagussss" are three different words but share the n-grams bag, agu, gus. With char_wb (n-grams inside word boundaries, ) the model also sees prefixes and suffixes such as meng-, -kan (frequent in formal derivation) or doubled letters.
The full solution
- Merge classes 1 to 5 into label 1.
- Features: the union of character 1-5-grams (case kept, sublinear TF-IDF) and whitespace tokens (case kept, so that ALL-CAPS shouting and punctuation glued to words like
semalam.stay visible). - Classifier:
LinearSVC(C=1). - Evaluate with 5-fold stratified cross-validation repeated 5 times (25 fits): with only 820 texts, one split has a standard deviation of about 0.01 F1, as large as the differences between models.
- Refit on all 820 texts and predict the 93 test texts.
chars = TfidfVectorizer(analyzer="char_wb", ngram_range=(1, 5), lowercase=False, sublinear_tf=True)
words = TfidfVectorizer(token_pattern=r"\S+", lowercase=False, sublinear_tf=True)
model = make_pipeline(make_union(chars, words), LinearSVC(C=1.0)).fit(X, y)
Error analysis. Out of 820 texts the out-of-fold predictions make 9 mistakes, and they are instructive. Most are pasar-labelled comments written in perfectly standard Malay ("Asalnya datang daripada penggunaan perkataan 'sarekat'...", a history comment about American colonies): they come from social media, but nothing in the text is colloquial. The baku errors are news sentences on everyday topics ("Hukumnya harus jika bermain..."). These are labelling ambiguities more than model failures, and no bag-of-words model will fix them.
Comparison with the contestant's submission. Our 93 test predictions agree with the predictions printed in the mirror notebook (the contestant's SGD model, for which they report a server score of 9.78, assuming the printed predictions are the ones scored) on 92 texts. On the remaining one (test id 47, an Indonesian question to an archaeologist that starts with "Pak" and contains "sperti") we predict baku and they predicted pasar. We can even pin our test score down to two values. Their score means : with 46 predicted positives, that is , one false positive and one false negative. If text 47 really is pasar, we have , , , so ; if it is baku, . Reading it, pasar looks more likely, so our honest estimate on the official test is about 0.967, against in cross-validation (a 93-text test set moves by 0.01 per error). We did not adjust the model to that one text: fixing a test prediction by hand would be tuning on the test set.
Results
| approach | F1 (pasar), 5 x 5 CV on train |
|---|---|
| predict everything pasar | 0.661 |
| rule: capital start + final period = baku | 0.764 |
| word TF-IDF without stopwords + SGD (the contestant's approach) | 0.980 0.012 |
| word counts + multinomial Naive Bayes | 0.983 0.012 |
| word TF-IDF + logistic regression | 0.985 0.011 |
| char 1-5 TF-IDF (lowercased) + linear SVM | 0.987 0.007 |
| char 1-5 + cased tokens + linear SVM (final) | 0.988 0.008 |
All linear models are within one standard deviation of each other: on a dataset this small, the feature representation matters much more than the choice of linear classifier, and the remaining errors are ambiguous labels. Removing stopwords slightly hurts, because the most informative pasar markers (tak, ni, je, la) are themselves stopwords.
What to remember
- Read the metric before modelling: F1 of the positive class gives 0 to an all-negative submission and ignores true negatives.
- Sparse text features + a linear model is the strong, fast baseline for short-text classification; on 820 examples it reaches about 0.985 F1.
- Character n-grams handle spelling variation (stretched letters, abbreviations, typos) that word features treat as unrelated words.
- Do not blindly remove stopwords: in register or style tasks, function words and particles carry the signal.
- Inspect the weights: they reveal shortcuts (here, news topics standing in for "standard language") that could break on data from other sources. With small data, use repeated cross-validation, since single-split differences are mostly noise.