First, deduping there is giving you invalid results. If there ARE any duplicate users, then you need to either retain them, or sort descending on count before deduping. (Also, as best practices, it's better to do those things before making the names "pretty".)
Make this your base
<search id="base">
<query>
index=main sourcetype="wineventlog" EventCode=4625 (Sub_Status=0xC000006A OR Sub_Status=0xC0000064)
| eval match=if(match(Account_Name,".*\$"),1,0)
| eval Description=if(Sub_Status=="0xC0000064","User name does not exist.","User name is correct but the password is wrong.")
| where match=0
| fields user, src_ip, src_nt_host, Description
</query>
</search>
Make this your second query
<search base="base">
<query>
| stats count AS "TotalAuthFailures" by user, src_ip, src_nt_host, Description
| search TotalAuthFailures >= 20
| sort 0 - TotalAuthFailures + user
| rename COMMENT as "dedup user here if you really need to"
| rename
user AS "User (Origin)",
src_ip AS "Source IP Address",
src_nt_host AS "Host (Origin)",
EventCode AS "Event ID"
</query>
</search>
Make this your third query
<search base="base">
<query>
| eventstats count AS "TotalAuthFailures" by user, src_ip, src_nt_host, Description
| search TotalAuthFailures >= 20
| fields - TotalAuthFailures
</query>
</search>
... View more