{"id":201620,"date":"2025-12-24T13:49:13","date_gmt":"2025-12-24T13:49:13","guid":{"rendered":"https:\/\/www.newsbeep.com\/il\/201620\/"},"modified":"2025-12-24T13:49:13","modified_gmt":"2025-12-24T13:49:13","slug":"the-machine-learning-advent-calendar-day-23-1d-cnn-for-text-in-excel","status":"publish","type":"post","link":"https:\/\/www.newsbeep.com\/il\/201620\/","title":{"rendered":"The Machine Learning \u201cAdvent Calendar\u201d Day 23: 1D CNN for Text in Excel"},"content":{"rendered":"<p class=\"wp-block-paragraph\"> were first introduced for images, and for images they are often easy to understand.<\/p>\n<p class=\"wp-block-paragraph\">A filter slides over pixels and detects edges, shapes, or textures. You can <a href=\"https:\/\/towardsdatascience.com\/understanding-convolutional-neural-networks-cnns-through-excel\/\" rel=\"nofollow noopener\" target=\"_blank\">read this article I wrote earlier<\/a> to understand how CNNs work for images with Excel.<\/p>\n<p class=\"wp-block-paragraph\">For text, the idea is the same.<\/p>\n<p class=\"wp-block-paragraph\">Instead of pixels, we slide filters over words.<\/p>\n<p class=\"wp-block-paragraph\">Instead of visual patterns, we detect linguistic patterns.<\/p>\n<p class=\"wp-block-paragraph\">And many important patterns in text are very local. Let\u2019s take these very simple examples:<\/p>\n<p>\u201cgood\u201d is positive<\/p>\n<p>\u201cbad\u201d is negative<\/p>\n<p>\u201cnot good\u201d is negative<\/p>\n<p>\u201cnot bad\u201d is often positive<\/p>\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/towardsdatascience.com\/the-machine-learning-advent-calendar-day-22-embeddings-in-excel\/\" rel=\"nofollow noopener\" target=\"_blank\">In my previous article<\/a>, we saw how to represent words as numbers using embeddings.<\/p>\n<p class=\"wp-block-paragraph\">We also saw a key limitation: when we used a global average, word order was completely ignored.<\/p>\n<p class=\"wp-block-paragraph\">From the model\u2019s point of view, \u201cnot good\u201d and \u201cgood not\u201d looked exactly the same.<\/p>\n<p class=\"wp-block-paragraph\">So the next challenge is clear: we want the model to take word order into account.<\/p>\n<p class=\"wp-block-paragraph\">A 1D Convolutional Neural Network is a natural tool for this, because it scans a sentence with small sliding windows and reacts when it recognizes familiar local patterns.<\/p>\n<p>1. Understanding a 1D CNN for Text: Architecture and Depth<\/p>\n<p>1.1. Building a 1D CNN for text in Excel<\/p>\n<p class=\"wp-block-paragraph\">In this article, we build a 1D CNN architecture in Excel with the following components:<\/p>\n<p>Embedding dictionary<br \/>We use a 2-dimensional embedding. Because one dimension is not enough for this task.<br \/>One dimension encodes sentiment, and the second dimension encodes negation.<\/p>\n<p>Conv1D layer<br \/>This is the core component of a CNN architecture.<br \/>It consists of filters that slide across the sentence with a window length of 2 words. We choose 2 words to be simple.<\/p>\n<p>ReLU and global max pooling<br \/>These steps keep only the strongest matches detected by the filters.<br \/>We will also discuss the fact that ReLU is optional.<\/p>\n<p>Logistic regression<br \/>This is the final classification layer, which combines the detected patterns into a probability.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/il\/wp-content\/uploads\/2025\/12\/image-419.png\" alt=\"\" class=\"wp-image-638858\"\/>1D CNN in Excel \u2013 all images by author<\/p>\n<p class=\"wp-block-paragraph\">This pipeline corresponds to a standard CNN text classifier.<br \/>The only difference here is that we explicitly write and visualize the forward pass in Excel.<\/p>\n<p>1.2. What \u201cdeep learning\u201d means in this architecture<\/p>\n<p class=\"wp-block-paragraph\">Before going further, let us take a step back.<br \/>Yes, I know, I do this often, but having a global view of models really helps to understand them.<\/p>\n<p class=\"wp-block-paragraph\">The definition of deep learning is often blurred.<br \/>For many people, deep learning simply means \u201cmany layers\u201d.<\/p>\n<p class=\"wp-block-paragraph\">Here, I will take a slightly different point of view.<\/p>\n<p class=\"wp-block-paragraph\">What really characterizes deep learning is not the number of layers, but the depth of the transformation applied to the input data.<\/p>\n<p class=\"wp-block-paragraph\">With this definition:<\/p>\n<p>Even a model with a single convolution layer can be considered deep learning,<\/p>\n<p>because the input is transformed into a more structured and abstract representation.<\/p>\n<p class=\"wp-block-paragraph\">On the other hand, taking raw input data, applying one-hot encoding, and stacking many fully connected layers does not necessarily make a model deep in a meaningful sense.<br \/>In theory, if we don\u2019t have any transformation, one layer is enough.<\/p>\n<p class=\"wp-block-paragraph\">In CNNs, the presence of multiple layers has a very concrete motivation.<\/p>\n<p class=\"wp-block-paragraph\">Consider a sentence like:<\/p>\n<p class=\"wp-block-paragraph\">This movie is not very good<\/p>\n<p class=\"wp-block-paragraph\">With a single convolution layer and a small window, we can detect simple local patterns such as: \u201cvery + good\u201d<\/p>\n<p class=\"wp-block-paragraph\">But we cannot yet detect higher-level patterns such as: \u201cnot + (very good)\u201d<\/p>\n<p class=\"wp-block-paragraph\">This is why CNNs are often stacked:<\/p>\n<p>the first layer detects simple local patterns,<\/p>\n<p>the second layer combines them into more complex ones.<\/p>\n<p class=\"wp-block-paragraph\">In this article, we deliberately focus on one convolution layer.<br \/>This makes every step visible and easy to understand in Excel, while keeping the logic identical to deeper CNN architectures.<\/p>\n<p>2. Turning words into embeddings<\/p>\n<p class=\"wp-block-paragraph\">Let us start with some simple words.\u00a0 We will try to detect negation, so we will use these terms, with other words (that we will not model)<\/p>\n<p>\u201cgood\u201d<\/p>\n<p>\u201cbad\u201d<\/p>\n<p>\u201cnot good\u201d<\/p>\n<p>\u201cnot bad\u201d<\/p>\n<p class=\"wp-block-paragraph\">We keep the representation intentionally small so that every step is visible.<\/p>\n<p class=\"wp-block-paragraph\">We will only use a dictionary of three words : good, bad and not.<\/p>\n<p class=\"wp-block-paragraph\">All other words will have 0 as embeddings.<\/p>\n<p>2.1 Why one dimension is not enough<\/p>\n<p class=\"wp-block-paragraph\">In a previous article on sentiment detection, we used a single dimension.<br \/>That worked for \u201cgood\u201d versus \u201cbad\u201d.<\/p>\n<p class=\"wp-block-paragraph\">But now we want to handle negation.<\/p>\n<p class=\"wp-block-paragraph\">One dimension can only represent one concept well.<br \/>So we need two dimensions:<\/p>\n<p>senti: sentiment polarity<\/p>\n<p>neg: negation marker<\/p>\n<p>2.2 The embedding dictionary<\/p>\n<p class=\"wp-block-paragraph\">Each word becomes a 2D vector:<\/p>\n<p>good \u2192 (senti = +1, neg = 0)<\/p>\n<p>bad \u2192 (senti = -1, neg = 0)<\/p>\n<p>not \u2192 (senti = 0, neg = +1)<\/p>\n<p>any other word \u2192 (0, 0)<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/il\/wp-content\/uploads\/2025\/12\/image-420-1024x591.png\" alt=\"\" class=\"wp-image-638859\"\/><\/p>\n<p class=\"wp-block-paragraph\">This is not how real embeddings look. Real embeddings are learned, high-dimensional, and not directly interpretable.<\/p>\n<p class=\"wp-block-paragraph\">But for understanding how Conv1D works, this toy embedding is perfect.<\/p>\n<p class=\"wp-block-paragraph\">In Excel, this is just a lookup table.<br \/>In a real neural network, this embedding matrix would be trainable.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/il\/wp-content\/uploads\/2025\/12\/image-421-1024x488.png\" alt=\"\" class=\"wp-image-638861\"\/><\/p>\n<p>3. Conv1D filters as sliding pattern detectors<\/p>\n<p class=\"wp-block-paragraph\">Now we arrive at the core idea of a 1D CNN.<\/p>\n<p class=\"wp-block-paragraph\">A Conv1D filter is nothing mysterious. It is just a small set of weights plus a bias that slides over the sentence.<\/p>\n<p class=\"wp-block-paragraph\">Because:<\/p>\n<p>each word embedding has 2 values (senti, neg)<\/p>\n<p>our window contains 2 words<\/p>\n<p class=\"wp-block-paragraph\">each filter has:<\/p>\n<p>4 weights (2 dimensions \u00d7 2 positions)<\/p>\n<p>1 bias<\/p>\n<p class=\"wp-block-paragraph\">That is all.<\/p>\n<p class=\"wp-block-paragraph\">You can think of a filter as repeatedly asking the same question at every position:<\/p>\n<p class=\"wp-block-paragraph\">\u201cDo these two neighboring words match a pattern I care about?\u201d<\/p>\n<p>3.1 Sliding windows: how Conv1D sees a sentence<\/p>\n<p class=\"wp-block-paragraph\">Consider this sentence:<\/p>\n<p class=\"wp-block-paragraph\">it is not bad at all<\/p>\n<p class=\"wp-block-paragraph\">We choose a window size of 2 words.<\/p>\n<p class=\"wp-block-paragraph\">That means the model looks at every adjacent pair:<\/p>\n<p>(it, is)<\/p>\n<p>(is, not)<\/p>\n<p>(not, bad)<\/p>\n<p>(bad, at)<\/p>\n<p>(at, all)<\/p>\n<p class=\"wp-block-paragraph\">Important point:<br \/>The filters slide everywhere, even when both words are neutral (all zeros).<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/il\/wp-content\/uploads\/2025\/12\/image-423-1024x546.png\" alt=\"\" class=\"wp-image-638866\"\/><\/p>\n<p>3.2 Four intuitive filters<\/p>\n<p class=\"wp-block-paragraph\">To make the behavior easy to understand, we use four filters.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/il\/wp-content\/uploads\/2025\/12\/image-424-1024x311.png\" alt=\"\" class=\"wp-image-638867\"\/><\/p>\n<p>Filter 1 \u2013 \u201cI see GOOD\u201d<\/p>\n<p class=\"wp-block-paragraph\">This filter looks only at the sentiment of the current word.<\/p>\n<p class=\"wp-block-paragraph\">Plain-text equation for one window:<\/p>\n<p class=\"wp-block-paragraph\">z = senti(current_word)<\/p>\n<p class=\"wp-block-paragraph\">If the word is \u201cgood\u201d, z = 1<br \/>If the word is \u201cbad\u201d, z = -1<br \/>If the word is neutral, z = 0<\/p>\n<p class=\"wp-block-paragraph\">After ReLU, negative values become 0. But it is optional.<\/p>\n<p>Filter 2 \u2013 \u201cI see BAD\u201d<\/p>\n<p class=\"wp-block-paragraph\">This one is symmetric.<\/p>\n<p class=\"wp-block-paragraph\">z = -senti(current_word)<\/p>\n<p class=\"wp-block-paragraph\">So:<\/p>\n<p>\u201cbad\u201d \u2192 z = 1<\/p>\n<p>\u201cgood\u201d \u2192 z = -1 \u2192 ReLU \u2192 0<\/p>\n<p>Filter 3 \u2013 \u201cI see NOT GOOD\u201d<\/p>\n<p class=\"wp-block-paragraph\">This filter looks at two things at the same time:<\/p>\n<p>neg(previous_word)<\/p>\n<p>senti(current_word)<\/p>\n<p class=\"wp-block-paragraph\">Equation:<\/p>\n<p class=\"wp-block-paragraph\">z = neg(previous_word) + senti(current_word) \u2013 1<\/p>\n<p class=\"wp-block-paragraph\">Why the \u201c-1\u201d?<br \/>It acts like a threshold so that both conditions must be true.<\/p>\n<p class=\"wp-block-paragraph\">Results:<\/p>\n<p>\u201cnot good\u201d \u2192 1 + 1 \u2013 1 = 1 \u2192 activated<\/p>\n<p>\u201cis good\u201d \u2192 0 + 1 \u2013 1 = 0 \u2192 not activated<\/p>\n<p>\u201cnot bad\u201d \u2192 1 \u2013 1 \u2013 1 = -1 \u2192 ReLU \u2192 0<\/p>\n<p>Filter 4 \u2013 \u201cI see NOT BAD\u201d<\/p>\n<p class=\"wp-block-paragraph\">Same idea, slightly different sign:<\/p>\n<p class=\"wp-block-paragraph\">z = neg(previous_word) + (-senti(current_word)) \u2013 1<\/p>\n<p class=\"wp-block-paragraph\">Results:<\/p>\n<p>\u201cnot bad\u201d \u2192 1 + 1 \u2013 1 = 1<\/p>\n<p>\u201cnot good\u201d \u2192 1 \u2013 1 \u2013 1 = -1 \u2192 0<\/p>\n<p class=\"wp-block-paragraph\">This is a very important intuition:<\/p>\n<p class=\"wp-block-paragraph\">A CNN filter can behave like a local logical rule, learned from data.<\/p>\n<p>3.3 Final result of sliding windows<\/p>\n<p class=\"wp-block-paragraph\">Here is the final results of these 4 filters.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/il\/wp-content\/uploads\/2025\/12\/image-425-1024x434.png\" alt=\"\" class=\"wp-image-638869\"\/><\/p>\n<p>4. ReLU and max pooling: from local to global<\/p>\n<p>4.1 ReLU<\/p>\n<p class=\"wp-block-paragraph\">After computing z for every window, we apply ReLU:<\/p>\n<p class=\"wp-block-paragraph\">ReLU(z) = max(0, z)<\/p>\n<p class=\"wp-block-paragraph\">Meaning:<\/p>\n<p>negative evidence is ignored<\/p>\n<p>positive evidence is kept<\/p>\n<p class=\"wp-block-paragraph\">Each filter becomes a presence detector.<\/p>\n<p class=\"wp-block-paragraph\">By the way, it is an activation function in the Neural network. So a Neural network is not that difficult after all.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/il\/wp-content\/uploads\/2025\/12\/image-425-1024x434.png\" alt=\"\" class=\"wp-image-638869\"\/><\/p>\n<p>4.2 Global Max pooling<\/p>\n<p class=\"wp-block-paragraph\">Then comes global max pooling.<\/p>\n<p class=\"wp-block-paragraph\">For each filter, we keep only:<\/p>\n<p class=\"wp-block-paragraph\">max activation over all windows<\/p>\n<p class=\"wp-block-paragraph\">Interpretation:<br \/>\u201cI do not care where the pattern appears, only whether it appears strongly somewhere.\u201d<\/p>\n<p class=\"wp-block-paragraph\">At this point, the whole sentence is summarized by 4 numbers:<\/p>\n<p>strongest \u201cgood\u201d signal<\/p>\n<p>strongest \u201cbad\u201d signal<\/p>\n<p>strongest \u201cnot good\u201d signal<\/p>\n<p>strongest \u201cnot bad\u201d signal<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/il\/wp-content\/uploads\/2025\/12\/image-427-1024x325.png\" alt=\"\" class=\"wp-image-638871\"\/><\/p>\n<p>4.3 What happens if we remove ReLU?<\/p>\n<p class=\"wp-block-paragraph\">Without ReLU:<\/p>\n<p>negative values stay negative<\/p>\n<p>max pooling may select negative values<\/p>\n<p class=\"wp-block-paragraph\">This mixes two ideas:<\/p>\n<p>absence of a pattern<\/p>\n<p>opposite of a pattern<\/p>\n<p class=\"wp-block-paragraph\">The filter stops being a clean detector and becomes a signed score.<\/p>\n<p class=\"wp-block-paragraph\">The model could still work mathematically, but interpretation becomes harder.<\/p>\n<p>5. The final layer is logistic regression<\/p>\n<p class=\"wp-block-paragraph\">Now we combine these signals.<\/p>\n<p class=\"wp-block-paragraph\">We compute a score using a linear combination:<\/p>\n<p class=\"wp-block-paragraph\">score = 2 \u00d7 F_good \u2013 2 \u00d7 F_bad \u2013 3 \u00d7 F_not_good \u2013 3 \u00d7 F_not_bad \u2013 bias<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/il\/wp-content\/uploads\/2025\/12\/image-429-1024x256.png\" alt=\"\" class=\"wp-image-638873\"\/><\/p>\n<p class=\"wp-block-paragraph\">Then we convert the score into a probability:<\/p>\n<p class=\"wp-block-paragraph\">probability = 1 \/ (1 + exp(-score))<\/p>\n<p class=\"wp-block-paragraph\">That is exactly logistic regression.<\/p>\n<p class=\"wp-block-paragraph\">So yes:<\/p>\n<p>the CNN extracts features: this step can be considered as feature engineering, right?<\/p>\n<p>logistic regression makes the final decisions, it is a classic machine learning model we know well<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/il\/wp-content\/uploads\/2025\/12\/image-432-1024x322.png\" alt=\"\" class=\"wp-image-638876\"\/><\/p>\n<p>6. Full examples with sliding filters<\/p>\n<p>Example 1<\/p>\n<p class=\"wp-block-paragraph\">\u201cit is bad, so it is not good at all\u201d<\/p>\n<p class=\"wp-block-paragraph\">The sentence contains:<\/p>\n<p class=\"wp-block-paragraph\">After max pooling:<\/p>\n<p>F_good = 1 (because \u201cgood\u201d exists)<\/p>\n<p>F_bad = 1<\/p>\n<p>F_not_good = 1<\/p>\n<p>F_not_bad = 0<\/p>\n<p class=\"wp-block-paragraph\">Final score becomes strongly negative.<br \/>Prediction: negative sentiment.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/il\/wp-content\/uploads\/2025\/12\/image-430-1024x358.png\" alt=\"\" class=\"wp-image-638874\"\/><\/p>\n<p>Example 2<\/p>\n<p class=\"wp-block-paragraph\">\u201cit is good. yes, not bad.\u201d<\/p>\n<p class=\"wp-block-paragraph\">The sentence contains:<\/p>\n<p class=\"wp-block-paragraph\">After max pooling:<\/p>\n<p>F_good = 1<\/p>\n<p>F_bad = 1 (because the word \u201cbad\u201d appears)<\/p>\n<p>F_not_good = 0<\/p>\n<p>F_not_bad = 1<\/p>\n<p class=\"wp-block-paragraph\">The final linear layer learns that \u201cnot bad\u201d should outweigh \u201cbad\u201d.<\/p>\n<p class=\"wp-block-paragraph\">Prediction: positive sentiment.<\/p>\n<p class=\"wp-block-paragraph\">This also shows something important: max pooling keeps all strong signals.<br \/>The final layer decides how to combine them.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/il\/wp-content\/uploads\/2025\/12\/image-431-1024x373.png\" alt=\"\" class=\"wp-image-638875\"\/><\/p>\n<p>Exemple 3 with A limitation that explains why CNNs get deeper<\/p>\n<p class=\"wp-block-paragraph\">Try this sentence:<\/p>\n<p class=\"wp-block-paragraph\">\u201cit is not very bad\u201d<\/p>\n<p class=\"wp-block-paragraph\">With a window of size 2, the model sees:<\/p>\n<p class=\"wp-block-paragraph\">It never sees (not, bad), so the \u201cnot bad\u201d filter never fires.<\/p>\n<p class=\"wp-block-paragraph\">It explains why real models use:<\/p>\n<p>larger windows<\/p>\n<p>multiple convolution layers<\/p>\n<p>or other architectures for longer dependencies<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.newsbeep.com\/il\/wp-content\/uploads\/2025\/12\/image-432-1024x322.png\" alt=\"\" class=\"wp-image-638876\"\/><\/p>\n<p>Conclusion<\/p>\n<p class=\"wp-block-paragraph\">The strength of Excel is visibility.<\/p>\n<p class=\"wp-block-paragraph\">You can see:<\/p>\n<p>the embedding dictionary<\/p>\n<p>all filter weights and biases<\/p>\n<p>every sliding window<\/p>\n<p>every ReLU activation<\/p>\n<p>the max pooling result<\/p>\n<p>the logistic regression parameters<\/p>\n<p class=\"wp-block-paragraph\">Training is simply the process of adjusting these numbers.<\/p>\n<p class=\"wp-block-paragraph\">Once you see that, CNNs stop being mysterious.<\/p>\n<p class=\"wp-block-paragraph\">They become what they really are: structured, trainable pattern detectors that slide over data.<\/p>\n","protected":false},"excerpt":{"rendered":"were first introduced for images, and for images they are often easy to understand. A filter slides over&hellip;\n","protected":false},"author":2,"featured_media":201621,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[20],"tags":[345,343,344,15394,10716,2158,85,46,1359,125],"class_list":["post-201620","post","type-post","status-publish","format-standard","has-post-thumbnail","category-artificial-intelligence","tag-ai","tag-artificial-intelligence","tag-artificialintelligence","tag-cnn","tag-data-science","tag-deep-learning","tag-il","tag-israel","tag-machine-learning","tag-technology"],"_links":{"self":[{"href":"https:\/\/www.newsbeep.com\/il\/wp-json\/wp\/v2\/posts\/201620","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.newsbeep.com\/il\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.newsbeep.com\/il\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.newsbeep.com\/il\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.newsbeep.com\/il\/wp-json\/wp\/v2\/comments?post=201620"}],"version-history":[{"count":0,"href":"https:\/\/www.newsbeep.com\/il\/wp-json\/wp\/v2\/posts\/201620\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.newsbeep.com\/il\/wp-json\/wp\/v2\/media\/201621"}],"wp:attachment":[{"href":"https:\/\/www.newsbeep.com\/il\/wp-json\/wp\/v2\/media?parent=201620"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.newsbeep.com\/il\/wp-json\/wp\/v2\/categories?post=201620"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.newsbeep.com\/il\/wp-json\/wp\/v2\/tags?post=201620"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}