Fine-Grained Emotion Classification from Mobile App Reviews: An Empirical Study with Large Language Models
Organizations: Department of Service and Information System Engineering, Universitat Politècnica de Catalunya, Spain
Abstract
Context: Fine-grained emotion classification of mobile app reviews enables requirements engineering activities that go beyond polarity-based opinion mining, including emotionally informed issue prioritisation and feature-oriented feedback analysis. However, automatic fine-grained emotion extraction from app reviews remains understudied. Objectives: Building on a previously published annotation framework and human-labelled ground truth adapted from Plutchik's taxonomy, this paper investigates how large language models can be leveraged for automatic multi-label emotion classification under severe class imbalance. Methods: We compare encoder-only fine-tuning under multi-label and binary-ensemble formulations, decoder-only zero- and few-shot prompting across open-source and proprietary models, and a catalogue of imbalance mitigation strategies (loss reweighting, resampling, generative data augmentation), with the synthetic-review generator and prompting strategy selected via an intrinsic augmentation-utility ranking. Results: Fine-tuned encoders trail the best decoder-only few-shot prompting (macro-F1 0.642) by a wide margin at baseline (multi-label: 0.387; binary ensemble: 0.450); pairing the best multi-label encoder with generative data augmentation and positive-weighted loss closes most of this gap (+0.204) at up to three orders of magnitude lower inference latency than the decoders, with the largest gains on the rarest emotions, from undetected to gains of up to +0.501 F1. Conclusion: Large language models make fine-grained, multi-label emotion classification of app reviews feasible for requirements engineering pipelines, with modest macro-F1, and the best formulation and mitigation strategy are backbone- and formulation-dependent. We release the experimental pipeline, synthetic corpora, and fine-tuned checkpoints for replication and reuse.
Figures & tables
| Resource | Lang. | Labels | Unit | Size | Annotation | Guidelines | Avail. |
| Motger et al. (2025b) | EN | Plutchik (8) + Neutral | Sentence | 1,090 | Human ( ) | Publicly released guidelines + examples | Yes |
| Riccosan and Saputra (2023) | ID | Shaver (5) + Neutral | Sentence | 21,697 | Human ( ) | Paper-level description | Yes |
| Siqueira et al. (2024) | PT | Ekman (6) + Neutral | Review | 3,000 | Human ( ) | Paper-level description | Yes |
| Singh and Suri (2022) | EN | Plutchik | Review | 2,000 | Automatic (lexicon-based) | Tool-oriented | No ‡ |
| Keertipati et al. (2016) | EN | LIWC negative emotions | Review | 4,442 | Automatic (lexicon-based) | Tool-oriented | No ‡ |
| Malgaonkar et al. (2019) | EN | Ekman (6) | Review | 52,705 | Automatic (lexicon-based) | Tool-oriented | No ‡ |
| Factor | RQ | Levels (summary) |
| Encoder backbone | RQ1, RQ4 | See Table 3 (base/large variants) |
| Classification head | RQ1, RQ4 | Multi-label (single model) vs. binary ensemble |
| Encoder training hyperparameters | RQ1, RQ4 | Learning rate (tuned per backbone); epochs 3; batch size 8; max length 512 |
| Decoder model | RQ2, RQ3 | See Table 3 (open-source and proprietary) |
| Prompting regime | RQ2, RQ3 | Zero-shot; few-shot (guidelines); few-shot (guidelines + dataset samples) |
| Decoding temperature | RQ2 | Sensitivity grid (default for primary tables) |
| Architecture | Access | Family | Variant | Identifier | Role |
| Encoder-only | Open-source | BERT | base | bert-base-cased | Fine-tune (RQ1, RQ4) |
| Open-source | BERT | large | bert-large-cased | Fine-tune (RQ1) | |
| Open-source | RoBERTa | base | roberta-base | Fine-tune (RQ1) | |
| Open-source | RoBERTa | large | roberta-large | Fine-tune (RQ1, RQ4) | |
| Open-source | DistilBERT | base | distilbert-base-cased | Fine-tune (RQ1) | |
| Open-source | DeBERTa-v3 | base | microsoft/deberta-v3-base | Fine-tune (RQ1) |
| Multi-label | Binary ensemble | |||||||
| Encoder | P | R | Macro-F1 | Micro-F1 | P | R | Macro-F1 | Micro-F1 |
| BERT | 0.332 | 0.337 | 0.329 0.039 | 0.644 | 0.484 | 0.450 | 0.450 0.077 | 0.670 |
| BERT | 0.417 | 0.383 | 0.387 0.047 | 0.671 | 0.463 | 0.448 | 0.440 0.063 | 0.673 |
| RoBERTa | 0.405 | 0.381 | 0.380 0.041 | 0.683 | 0.326 | 0.348 | 0.327 0.052 | 0.641 |
| RoBERTa | 0.410 | 0.390 | 0.387 0.032 | 0.697 | 0.413 | 0.415 | 0.404 0.054 | 0.696 |
| DistilBERT | 0.380 | 0.351 | 0.353 0.050 | 0.633 | 0.406 | 0.401 | 0.395 0.046 | 0.638 |
| Multi-label | Binary ensemble | ||||||
| Emotion | Support | P | R | F1 | P | R | F1 |
| Joy | 371 | 0.826 | 0.786 | 0.804 | 0.763 | 0.808 | 0.784 |
| Sadness | 303 | 0.673 | 0.861 | 0.755 | 0.702 | 0.784 | 0.738 |
| Anticipation | 181 | 0.798 | 0.794 | 0.791 | 0.728 | 0.820 | 0.765 |
| Trust | 152 | 0.669 | 0.731 | 0.694 | 0.685 | 0.617 | 0.644 |
| Neutral | 88 | 0.528 | 0.255 | 0.322 | 0.520 | 0.341 | 0.384 |
| Encoder | Multi-label (ms) | Binary ensemble (ms) |
| BERT | 0.38 | 3.45 |
| BERT | 1.10 | 9.90 |
| RoBERTa | 0.38 | 3.43 |
| RoBERTa | 1.08 | 9.74 |
| DistilBERT | 0.21 | 1.88 |
| DeBERTa-v3 | 0.72 | 4.73 |
| Decoder | Strategy | P | R | Macro-F1 | Micro-F1 |
| Proprietary | |||||
| Gemini-3.5-Flash | Zero-shot | 0.603 | 0.647 | 0.605 | 0.744 |
| Few-shot (guid.) | 0.595 | 0.638 | 0.594 | 0.753 | |
| Few-shot (dataset) | 0.637 | 0.685 | 0.642 | 0.767 | |
| GPT-5.2 | Zero-shot | 0.538 | 0.575 | 0.528 | 0.669 |
| Few-shot (guid.) | 0.559 | 0.582 | 0.542 | 0.681 | |
| Decoder | Range | |||
| Gemini-3.5-Flash | 0.642 | 0.649 | 0.628 | 0.021 |
| GPT-5.2 | 0.577 | 0.573 | 0.570 | 0.007 |
| Claude-Opus-4.6 | 0.544 | 0.545 | 0.545 | 0.001 |
| Mistral-Large | 0.504 | 0.505 | 0.509 | 0.005 |
| GPT-OSS-20B | 0.526 | 0.508 | 0.532 | 0.024 |
| Qwen3-8B | 0.461 | 0.467 | 0.439 | 0.028 |
| Decoder | Prompt tok. | Compl. tok. | Latency (s) |
| Gemini-3.5-Flash | 571 | 31 | 1.21 |
| GPT-5.2 | 540 | 19 | 0.23 |
| Claude-Opus-4.6 | 598 | 28 | 0.24 |
| Mistral-Large | 567 | 24 | 0.42 |
| GPT-OSS-20B | 542 | 130 | 0.80 |
| Qwen3-8B | 447 | 145 | 1.13 |
| Gemini-3.5-Flash | GPT-OSS-20B | ||||||
| Emotion | Support | P | R | F1 | P | R | F1 |
| Joy | 371 | 0.839 | 0.820 | 0.827 | 0.829 | 0.714 | 0.762 |
| Sadness | 303 | 0.814 | 0.845 | 0.829 | 0.787 | 0.859 | 0.820 |
| Anticipation | 181 | 0.803 | 0.895 | 0.844 | 0.788 | 0.773 | 0.771 |
| Trust | 152 | 0.728 | 0.828 | 0.764 | 0.728 | 0.540 | 0.611 |
| Neutral | 88 | 0.591 | 0.764 | 0.661 | 0.476 | 0.683 | 0.552 |
| Rank | Strategy | Generator | Div. | Nov. (synth) | Nov. (GT) | On-emo. | Borda |
| 1 | Few-shot (dataset) | claude-opus-4-6 | 0.743 | 0.539 | 0.513 | 0.431 | 38 |
| 2 | Few-shot (guidelines) | mistral-large-2512 | 0.739 | 0.504 | 0.570 | 0.357 | 34 |
| 3 | Few-shot (guidelines) | claude-opus-4-6 | 0.727 | 0.518 | 0.511 | 0.429 | 33 |
| 4 | Few-shot (dataset) | gemini-3.5-flash | 0.716 | 0.499 | 0.559 | 0.384 | 30 |
| 5 | Few-shot (guidelines) | gemini-3.5-flash | 0.702 | 0.502 | 0.534 | 0.422 | 29 |
| 6 | Zero-shot | claude-opus-4-6 | 0.695 | 0.476 | 0.553 | 0.395 | 27 |
| Multi-label | Binary ensemble | |||||||
| Configuration | P | R | Macro-F1 | Micro-F1 | P | R | Macro-F1 | Micro-F1 |
| Baseline (none) | 0.410 | 0.390 | 0.387 0.032 | 0.697 | 0.484 | 0.450 | 0.450 0.077 | 0.670 |
| Loss reweighting | ||||||||
| BCE + pos. weight (L1) | 0.242 | 0.527 | 0.303 0.151 | 0.443 | 0.361 | 0.378 | 0.359 0.044 | 0.632 |
| BCE + class weight (L2) | 0.206 | 0.214 | 0.185 0.120 | 0.476 | 0.355 | 0.360 | 0.345 0.023 | 0.635 |
| Focal loss (L3) | 0.396 | 0.728 | 0.462 0.021 | 0.553 | 0.442 | 0.551 | 0.461 0.039 | 0.606 |
| Baseline | Best config. | |||||||
| Emotion | Support | P | R | F1 | P | R | F1 | F1 |
| Joy | 371 | 0.826 | 0.786 | 0.804 | 0.750 | 0.878 | 0.806 | +0.002 |
| Sadness | 303 | 0.673 | 0.861 | 0.755 | 0.713 | 0.842 | 0.771 | +0.016 |
| Anticipation | 181 | 0.798 | 0.794 | 0.791 | 0.764 | 0.885 | 0.815 | +0.024 |
| Trust | 152 | 0.669 | 0.731 | 0.694 | 0.639 | 0.847 | 0.720 | +0.026 |
| Neutral | 88 | 0.528 | 0.255 | 0.322 | 0.537 | 0.538 | 0.507 | +0.185 |