diff --git a/CHANGELOG.md b/CHANGELOG.md
index 490f3f7f1482716d7cd128c28e68acc1f31870a7..44965ad94fdedbe16459d6087d302d1b89532089 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -40,6 +40,7 @@ release.
 - Added Vectorize to ProcessGroundPolygon library
 - Added gtest files for the app and unit test 
 - Added Chandrayaan2 template for isisimport
+- Added majority replacement for reduce app [#5101](https://github.com/DOI-USGS/ISIS3/issues/5101).
 - Added HRSC support in socetlinescankeywords [#5465](https://github.com/DOI-USGS/ISIS3/issues/5465)
 
 ### Changed
diff --git a/isis/src/base/apps/reduce/reduce.xml b/isis/src/base/apps/reduce/reduce.xml
index e53f5845c092eea24e80f78e363f45789c3d7f52..65eb9ff79e7aa099cce6ed2762dd0202725f2ac8 100644
--- a/isis/src/base/apps/reduce/reduce.xml
+++ b/isis/src/base/apps/reduce/reduce.xml
@@ -334,6 +334,13 @@
 	      is closest to the center of the window being analyzed.
     	    </description>
     	  </option>
+        <option value="MAJORITY">
+          <brief>Majority replacement</brief>
+          <description>
+            When VALIDPER is not met, propagate the most commonly occurring special pixel
+            within the input region to the output pixel.
+          </description>
+        </option>
     	</list>
       </parameter>
     </group>
diff --git a/isis/src/base/objs/Reduce/Reduce.cpp b/isis/src/base/objs/Reduce/Reduce.cpp
index f6210eb7f260c83d5cbf38817421c5268aac778b..7c1723bd2bbeb29d3f224c63e2959d0da024cfec 100644
--- a/isis/src/base/objs/Reduce/Reduce.cpp
+++ b/isis/src/base/objs/Reduce/Reduce.cpp
@@ -171,9 +171,11 @@ namespace Isis {
    */
   void Average::operator() (Isis::Buffer & out) const
   {
+    // Index of the last input line that corresponds to this output line.
     double rline = (double)out.Line() * mdLineScale;
 
     if(out.Line() == 1 && out.Band() == 1) {
+      // Index of the last input sample that corresponds to the output sample.
       mdIncTab = new double[miOutputSamples];
       mdSum    = new double[miOutputSamples];
       mdNpts   = new double[miOutputSamples];
@@ -191,7 +193,9 @@ namespace Isis {
       mdIncTab[miOutputSamples-1] = miInputSamples;
     }
 
-    while(mdLine <= rline) {
+    unordered_map<QString, int> specialPixelCounts[miOutputSamples];
+
+    while(mdLine < rline) {
       if((int)mdLine <= miInputLines) {
         m_iPortal->SetPosition(miStartSample, mdLine, miBandIndex);
         mInCube->read(*m_iPortal);
@@ -204,6 +208,9 @@ namespace Isis {
             mdSum[osamp]  += (*m_iPortal)[isamp-1];
             mdNpts[osamp] += 1.0;
           }
+          if (IsSpecial((*m_iPortal)[isamp-1])) {
+            specialPixelCounts[osamp][PixelToString((*m_iPortal)[isamp-1])]++;
+          } 
           isamp++;
         }
 
@@ -218,6 +225,12 @@ namespace Isis {
             mdNpts[osamp+1] += sdel;
           }
         }
+        if (IsSpecial((*m_iPortal)[isamp-1])) {
+          specialPixelCounts[osamp][PixelToString((*m_iPortal)[isamp-1])]++;
+          if(osamp+1 <= miOutputSamples){
+            specialPixelCounts[osamp+1][PixelToString((*m_iPortal)[isamp-1])]++;
+          }
+        } 
         isamp++;
       }
       mdLine++;
@@ -238,6 +251,9 @@ namespace Isis {
           mdSum2[osamp]  += (*m_iPortal)[isamp-1] * ldel;
           mdNpts2[osamp] += ldel;
         }
+        if (IsSpecial((*m_iPortal)[isamp-1])) {
+          specialPixelCounts[osamp][PixelToString((*m_iPortal)[isamp-1])]++;
+        } 
         isamp++;
       }
 
@@ -257,6 +273,12 @@ namespace Isis {
           mdNpts2[osamp+1] += sdel * ldel;
         }
       }
+      if (IsSpecial((*m_iPortal)[isamp-1])) {
+        specialPixelCounts[osamp][PixelToString((*m_iPortal)[isamp-1])]++;
+        if(osamp+1 <= miOutputSamples){
+          specialPixelCounts[osamp+1][PixelToString((*m_iPortal)[isamp-1])]++;
+        }
+      } 
       isamp++;
     }
 
@@ -271,6 +293,14 @@ namespace Isis {
         if(msReplaceMode == "NEAREST") {
           out[osamp] = (*m_iPortal)[(int)(mdIncTab[osamp] + 0.5) - 1];
         }
+        else if (msReplaceMode == "MAJORITY") {
+          // Iterate over the map and compare element counts
+          // Map iterator yields a pair:  pair.first == pixel names, pair.second == pixel count.
+          auto mode = std::max_element(specialPixelCounts[osamp].begin(),
+                                      specialPixelCounts[osamp].end(),
+                                      [](const pair<QString, int> &a, const pair<QString, int> &b) {return a.second < b.second;});
+          out[osamp] = StringToPixel(mode->first);
+        }
         else {
           out[osamp] = Isis::Null;
         }
@@ -281,6 +311,7 @@ namespace Isis {
       mdNpts2[osamp] = 0.0;
     }
 
+    // If this is the last line of the band, reset stats and increment band
     if(out.Line() == miOutputLines && out.Band() != miInputBands) {
       miBandIndex++;
       mdLine = 1;
diff --git a/isis/src/base/objs/Reduce/Reduce.h b/isis/src/base/objs/Reduce/Reduce.h
index 9a6f1dd408df6bb1c1ef888729c2cdf8f2e7a812..d69e347ceaaf3f429e39dc88075f147af2a038c5 100644
--- a/isis/src/base/objs/Reduce/Reduce.h
+++ b/isis/src/base/objs/Reduce/Reduce.h
@@ -111,7 +111,7 @@ namespace Isis {
               double pdValidPer, QString psReplaceMode)
       : Reduce(pInCube, pdSampleScale, pdLineScale){
         mdValidPer    = pdValidPer;
-        msReplaceMode = psReplaceMode;
+        msReplaceMode = psReplaceMode.toUpper();
       }
 
       //! Operator () overload