Calculate daily rate of app description edits and reverted edits

# Split off from https://paws.wmflabs.org/paws/user/HaeB/notebooks/Mobile%20app%20edits%20on%20Wikidata.ipynb
# cf. http://paws-public.wmflabs.org/paws-public/User:Jtmorgan/ds4ux/paws-cheatsheet.ipynb
import os 
"""
Your db login credentials are stored in os.environ. 
DO NOT print or run os.environ, or it will expose your credentials in the Notebook
"""
import pymysql
import pandas as pd
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
from collections import defaultdict
import collections
import re

# cf. http://paws-public.wmflabs.org/paws-public/User:EpochFail/editquality/ipython/reverted_detection_demo.ipynb :
import sys, traceback
import mwreverts.api
import mwapi

# cf. http://paws-public.wmflabs.org/paws-public/User:EpochFail/editquality/ipython/reverted_detection_demo.ipynb :

session = mwapi.Session("https://www.wikidata.org", 
                        user_agent="Revert detection using mwapi (tbayer@wikimedia.org)")
%%time
!date

#get all app edits

conn2 = pymysql.connect(
    host=os.environ['MYSQL_HOST'],
    user=os.environ['MYSQL_USERNAME'],
    password=os.environ['MYSQL_PASSWORD'],
    database='wikidatawiki_p',
    charset='utf8'
)

with conn2.cursor() as cur:
    cur.execute("""
    SELECT rev_id, rev_timestamp, rev_comment, rev_user_text, rev_user FROM wikidatawiki_p.revision AS rev
    JOIN wikidatawiki_p.change_tag AS ct
    ON rev.rev_id = ct.ct_rev_id AND ct.ct_tag = "mobile app edit"
    ORDER BY rev_timestamp;""")
    appedits = cur.fetchall()
Wed May  9 04:18:35 UTC 2018
CPU times: user 3.42 s, sys: 288 ms, total: 3.71 s
Wall time: 1min 51s
#check result
print(len(appedits))
print(appedits[0])
print(appedits[-1])
print(appedits[1200:1209])
171018
(181261717, b'20141215123456', b'/* wbsetdescription-add:1|en */ A town in Minnesota, USA', b'208.54.5.139', 0)
(675786527, b'20180508060548', b'/* wbsetdescription-remove:1|es */ 2018', b'Jose34683', 2844537)
((423259471, b'20170101203544', b'/* wbsetdescription-set:1|en */ This is a sandbox for testing changes to items. Please be gentle with it. Feel free to change anything on this page! For testing links, try adding ones to userpages.', b'Alva1234567890', 2779682), (423889596, b'20170103205551', b'/* wbsetdescription-set:1|en */ species of fungus', b'74.111.100.186', 0), (423890267, b'20170103205700', b'/* wbsetdescription-set:1|en */ species of edible fungus', b'DBrant (WMF)', 890729), (423891075, b'20170103205822', b'/* wbsetdescription-set:1|en */ species of edible mushrooms', b'DBrant (WMF)', 890729), (423908849, b'20170103213655', b'/* wbsetdescription-set:1|en */ genus of extinct mammals', b'DBrant (WMF)', 890729), (423926260, b'20170103221609', b'/* wbsetdescription-set:1|en */ extinct genus of mammals', b'68.40.255.173', 0), (424077989, b'20170104035752', b'/* wbsetdescription-add:1|en */ sex', b'41.113.247.183', 0), (424081597, b'20170104041124', b'/* wbsetdescription-add:1|en */ Give more porn', b'41.114.197.192', 0), (424139059, b'20170104085603', b'/* wbsetdescription-add:1|en */ north-south street in San Francisco, main business area of Chinatown', b'HaeB', 143824))
%%time
# calculate daily revert rate for a range of dates
!date

# initialize dataframes to count reverts per day:
daterange =  pd.date_range(start='2016-12-31', end='2018-05-05', freq='D')
columns = ['all', 'reverted', 'reverted_rate']  # each refers to the number of edits
# could add: number of revertees and reverters

try:
    del(revperday)
except NameError:
    pass
revperday = pd.DataFrame(index=daterange, columns=columns)
revperday = revperday.fillna(0)
# tack on daily list of reverters with revert count for each:
revperday['reverters'] = [defaultdict(int) for i in range(len(revperday.index))]

try:
    del(revperdaylang)
except NameError:
    pass
revperdaylang = pd.DataFrame(index=daterange, columns=columns)

for col in revperdaylang:
    revperdaylang[col] = [defaultdict(int) for i in range(len(revperdaylang.index))]
    
# kind of clumsy, but can't get fillna() or other more elegant options (below) to work:
# this works too:
# for i in range(len(revperdaylang.index)):
#    for c in range(len(revperdaylang.columns)):
#        revperdaylang.loc[revperdaylang.index[i]][revperdaylang.columns[c]] = defaultdict(int)
# these do NOT work:
# revperdaylang = revperdaylang.fillna(defaultdict(int))
# revperdaylang = revperdaylang.fillna(value=defaultdict(int), inplace=True)

# for i in revperdaylang.index:
#    for c in revperdaylang.columns:        
#        # revperdaylang[i][c] = defaultdict(int)
#        # revperdaylang.loc[i,c] = defaultdict(int)
        

anonedits = 0
anonreverted = 0
loginedits = 0
loginreverted = 0


# count reverts per day:
for rev in appedits:
    day = pd.to_datetime(rev[1][:8].decode())
    
    if day in daterange:
        
        revperday.loc[day,'all'] += 1
        
        try:
            lang = re.match(r'[^\|]*\|([^ ]*)',rev[2].decode()).group(1)      
        except AttributeError:
            lang = 'unknown'
        
        revperdaylang.loc[day,'all'][lang] +=1
        
        
        isanon = (rev[4] == 0) 
        
        if isanon:
            anonedits +=1
        else:
            loginedits +=1
        
        rev_id = rev[0]
        # from http://paws-public.wmflabs.org/paws-public/User:EpochFail/editquality/ipython/reverted_detection_demo.ipynb :
        try:
            _, reverted, reverted_to = mwreverts.api.check(
                session, rev_id, radius=5,  # most reverts happen within 5 edits
                window=48*60*60,  # 2 days
                rvprop={'user', 'ids'})  # Some properties we may make use of later
        except RuntimeError as e:
            sys.stderr.write(str(e))
            continue
        
        # count includes the special cases of self-reverts and reverts that were re-reverted
        # (one may want to leave these out later)
        
        if reverted:
            revperday.loc[day,'reverted'] += 1            
            revperdaylang.loc[day,'reverted'][lang] +=1
            
            reverter = reverted.reverting['user']
            # for debugging/checking:
            # print(reverter, 'reverted https://www.wikidata.org/w/index.php?diff=' + str(rev[0]))
            revperday.loc[day,'reverters'][reverter] += 1

            if isanon:
                anonreverted +=1
            else:
                loginreverted +=1

revperday['reverted_rate'] = revperday['reverted'] / revperday['all']



# Todo: use db instead of API for better performance
# after https://github.com/mediawiki-utilities/python-mwreverts/issues/8 has been fixed
Wed May  9 15:47:00 UTC 2018
CPU times: user 1h 18s, sys: 2min 48s, total: 1h 3min 7s
Wall time: 7h 50min 4s
#check result:
revperdaylang.tail(100)
all reverted reverted_rate
2018-01-26 {'he': 4, 'es': 45, 'fr': 13, 'ru': 20, 'de': ... {'ru': 4, 'de': 6, 'it': 8, 'hr': 2, 'fa': 7, ... {}
2018-01-27 {'pl': 4, 'es': 32, 'de': 39, 'it': 18, 'zh-ha... {'pt': 3, 'mr': 1, 'sv': 1, 'nl': 1, 'ta': 1, ... {}
2018-01-28 {'es': 106, 'de': 107, 'vi': 6, 'ru': 21, 'it'... {'ru': 7, 'bn': 2, 'vi': 2, 'es': 13, 'ja': 1,... {}
2018-01-29 {'hi': 5, 'it': 19, 'arz': 1, 'de': 256, 'es':... {'gu': 1, 'it': 8, 'hi': 2, 'de': 4, 'fa': 5, ... {}
2018-01-30 {'ja': 17, 'ru': 13, 'de': 92, 'pt': 17, 'ar':... {'de': 9, 'nl': 1, 'ca': 1, 'es': 5, 'my': 2, ... {}
2018-01-31 {'it': 18, 'ja': 2, 'ko': 5, 'es': 90, 'ar': 1... {'fa': 3, 'es': 15, 'pt': 2, 'ru': 7, 'it': 1,... {}
2018-02-01 {'es': 27, 'cs': 12, 'eo': 1, 'he': 6, 'pt': 3... {'eo': 1, 'pt': 1, 'fr': 4, 'sv': 1, 'fa': 4, ... {}
2018-02-02 {'ja': 15, 'fr': 13, 'ar': 23, 'cs': 1, 'pt': ... {'ar': 15, 'cs': 1, 'ms': 2, 'pt': 3, 'hi': 3,... {}
2018-02-03 {'ja': 2, 'fr': 19, 'fa': 2, 'es': 44, 'ar': 1... {'fr': 4, 'es': 3, 'pl': 2, 'it': 3, 'nl': 3, ... {}
2018-02-04 {'de': 35, 'fr': 18, 'pl': 5, 'it': 27, 'es': ... {'fr': 7, 'de': 1, 'id': 1, 'bn': 2, 'nl': 1, ... {}
2018-02-05 {'es': 52, 'it': 21, 'fr': 18, 'nl': 58, 'fa':... {'fr': 4, 'it': 6, 'ar': 4, 'fa': 3, 'ja': 1, ... {}
2018-02-06 {'es': 43, 'ja': 13, 'ar': 22, 'de': 39, 'fr':... {'fr': 8, 'hi': 1, 'ru': 4, 'ko': 4, 'fa': 4, ... {}
2018-02-07 {'es': 57, 'de': 32, 'pt': 9, 'kn': 1, 'ja': 7... {'es': 18, 'kn': 1, 'fa': 3, 'my': 1, 'de': 2,... {}
2018-02-08 {'pt': 11, 'fa': 24, 'es': 50, 'cs': 1, 'ru': ... {'ko': 3, 'tr': 1, 'vi': 1, 'ar': 11, 'ja': 1,... {}
2018-02-09 {'es': 42, 'fr': 16, 'nl': 20, 'simple': 1, 'i... {'es': 2, 'id': 3, 'cs': 1, 'fr': 2, 'fa': 1, ... {}
2018-02-10 {'es': 33, 'fr': 24, 'it': 18, 'fa': 11, 'zh-h... {'es': 7, 'ru': 3, 'hi': 3, 'fi': 2, 'fr': 3, ... {}
2018-02-11 {'es': 58, 'cs': 20, 'zh-hans': 2, 'de': 114, ... {'cdo': 1, 'es': 3, 'ru': 2, 'yi': 1, 'simple'... {}
2018-02-12 {'pt': 7, 'es': 48, 'zh-hans': 1, 'ja': 6, 'zh... {'es': 6, 'ar': 11, 'ru': 1, 'nl': 1, 'ca': 1,... {}
2018-02-13 {'pl': 3, 'is': 1, 'it': 31, 'ar': 23, 'de': 4... {'pl': 1, 'it': 4, 'ar': 4, 'mn': 1, 'fa': 7, ... {}
2018-02-14 {'ar': 9, 'es': 48, 'id': 5, 'sq': 1, 'ja': 5,... {'ar': 6, 'sv': 1, 'de': 2, 'hi': 4, 'fr': 1, ... {}
2018-02-15 {'pt': 7, 'de': 70, 'he': 13, 'nl': 11, 'hu': ... {'es': 11, 'fa': 4, 'ar': 9, 'ja': 1, 'ru': 3,... {}
2018-02-16 {'ar': 14, 'de': 64, 'es': 32, 'ml': 2, 'it': ... {'ar': 4, 'es': 3, 'th': 2, 'sh': 1, 'fa': 4, ... {}
2018-02-17 {'es': 71, 'ar': 27, 'kn': 1, 'ja': 13, 'pt': ... {'bn': 4, 'pt': 2, 'fa': 2, 'es': 4, 'fr': 3, ... {}
2018-02-18 {'pt': 14, 'ar': 18, 'es': 68, 'fr': 12, 'bn':... {'ar': 1, 'fr': 3, 'hi': 2, 'ja': 1, 'ceb': 1,... {}
2018-02-19 {'pl': 5, 'he': 12, 'es': 53, 'pt': 6, 'de': 4... {'hi': 3, 'ru': 3, 'ar': 2, 'af': 1, 'fa': 3, ... {}
2018-02-20 {'hi': 7, 'de': 39, 'ru': 23, 'es': 41, 'ne': ... {'hi': 7, 'ru': 5, 'de': 7, 'fa': 5, 'fr': 4, ... {}
2018-02-21 {'ml': 2, 'es': 64, 'ru': 23, 'ko': 5, 'fr': 1... {'ru': 1, 'es': 5, 'bn': 3, 'de': 8, 'id': 1, ... {}
2018-02-22 {'fr': 20, 'nl': 10, 'as': 1, 'ar': 27, 'es': ... {'as': 1, 'es': 6, 'it': 7, 'zh-hans': 1, 'fa'... {}
2018-02-23 {'de': 45, 'pt': 2, 'ru': 19, 'es': 44, 'tr': ... {'es': 2, 'fa': 4, 'zh': 1, 'ceb': 1, 'it': 4,... {}
2018-02-24 {'ru': 23, 'fr': 20, 'es': 24, 'gu': 1, 'arz':... {'ar': 15, 'fa': 1, 'ja': 1, 'hi': 2, 'de': 4,... {}
... ... ... ...
2018-04-06 {'pt': 22, 'da': 1, 'es': 148, 'it': 70, 'ko':... {'es': 3, 'it': 3, 'rm': 1, 'pt': 3, 'ru': 5, ... {}
2018-04-07 {'es': 91, 'vi': 1, 'ar': 29, 'fr': 15, 'pt': ... {'hi': 4, 'ru': 8, 'de': 3, 'ur': 1, 'zh-hant'... {}
2018-04-08 {'he': 10, 'ne': 1, 'qu': 1, 'th': 1, 'fr': 11... {'th': 1, 'it': 2, 'pt': 1, 'fa': 6, 'zh-hans'... {}
2018-04-09 {'es': 157, 'it': 22, 'qu': 3, 'ta': 2, 'ja': ... {'bn': 2, 'ja': 2, 'si': 1, 'id': 4, 'zh-hans'... {}
2018-04-10 {'fr': 14, 'ar': 11, 'he': 25, 'za': 2, 'es': ... {'za': 1, 'fa': 9, 'ms': 2, 'ta': 1, 'zh-hans'... {}
2018-04-11 {'es': 47, 'de': 26, 'ar': 24, 'hi': 4, 'te': ... {'bn': 1, 'de': 4, 'el': 1, 'fa': 6, 'ru': 5, ... {}
2018-04-12 {'es': 113, 'zh-hans': 4, 'pt': 13, 'de': 48, ... {'es': 9, 'pt': 1, 'bh': 3, 'ru': 5, 'ta': 1, ... {}
2018-04-13 {'es': 42, 'pt': 7, 'id': 5, 'he': 17, 'fr': 1... {'es': 9, 'id': 1, 'ru': 5, 'fa': 4, 'sk': 1, ... {}
2018-04-14 {'it': 50, 'es': 71, 'ar': 37, 'pt': 14, 'ru':... {'fr': 4, 'nl': 1, 'ru': 3, 'pt': 1, 'it': 2, ... {}
2018-04-15 {'pl': 90, 'es': 59, 'he': 14, 'it': 19, 'id':... {'es': 7, 'fa': 5, 'pt': 2, 'ru': 3, 'it': 1, ... {}
2018-04-16 {'es': 65, 'de': 70, 'bn': 4, 'ar': 20, 'fi': ... {'es': 7, 'de': 4, 'it': 2, 'ro': 1, 'hi': 1, ... {}
2018-04-17 {'de': 74, 'ar': 32, 'es': 61, 'bg': 2, 'pt': ... {'es': 14, 'hi': 1, 'ru': 11, 'te': 1, 'pt': 1... {}
2018-04-18 {'es': 53, 'da': 1, 'su': 1, 'de': 47, 'pt': 6... {'es': 11, 'su': 1, 'vec': 1, 'hi': 3, 'bn': 3... {}
2018-04-19 {'de': 84, 'es': 67, 'rmy': 1, 'ar': 40, 'fa':... {'fa': 4, 'ru': 8, 'hi': 1, 'es': 4, 'ja': 1, ... {}
2018-04-20 {'ja': 5, 'vi': 2, 'de': 28, 'qu': 2, 'ar': 30... {'es': 3, 'fa': 3, 'ja': 1, 'az': 3, 'ru': 7, ... {}
2018-04-21 {'fr': 14, 'ar': 30, 'es': 161, 'th': 1, 'pt':... {'pt': 2, 'bs': 1, 'nl': 1, 'de': 4, 'es': 5, ... {}
2018-04-22 {'es': 83, 'fa': 24, 'ja': 9, 'ar': 23, 'it': ... {'es': 7, 'fa': 5, 'pt': 3, 'it': 1, 'ca': 1, ... {}
2018-04-23 {'he': 53, 'ar': 31, 'es': 46, 'zh-tw': 1, 'pt... {'es': 3, 'pt': 3, 'id': 1, 'fi': 1, 'it': 6, ... {}
2018-04-24 {'sh': 1, 'fr': 21, 'es': 54, 'it': 127, 'zh-h... {'ja': 1, 'fa': 4, 'ace': 1, 'fi': 1, 'tl': 1,... {}
2018-04-25 {'ar': 20, 'es': 60, 'pt': 6, 'fa': 25, 'vi': ... {'fa': 8, 'de': 5, 'hi': 3, 'fr': 4, 'hu': 5, ... {}
2018-04-26 {'eo': 1, 'fa': 31, 'es': 49, 'hi': 3, 'ko': 2... {'es': 8, 'fa': 5, 'pt': 2, 'ru': 4, 'pnt': 1,... {}
2018-04-27 {'id': 4, 'ar': 14, 'hi': 4, 'es': 43, 'ko': 4... {'es': 3, 'fa': 3, 'ar': 6, 'hi': 2, 'ru': 2, ... {}
2018-04-28 {'de': 45, 'ar': 23, 'es': 46, 'ru': 15, 'sv':... {'hi': 2, 'de': 2, 'fr': 6, 'hu': 1, 'bh': 1, ... {}
2018-04-29 {'it': 22, 'es': 129, 'pt': 17, 'de': 28, 'fr'... {'ja': 2, 'es': 5, 'fa': 2, 'ar': 3, 'mr': 1, ... {}
2018-04-30 {'es': 76, 'fr': 16, 'pt': 10, 'de': 43, 'hi':... {'fr': 4, 'hi': 1, 'fa': 3, 'id': 1, 'sv': 8, ... {}
2018-05-01 {'de': 43, 'pt': 19, 'ca': 3, 'ko': 4, 'gl': 1... {'pt': 1, 'be': 1, 'fa': 10, 'de': 6, 'id': 2,... {}
2018-05-02 {'pt': 10, 'es': 56, 'fa': 10, 'bn': 7, 'sv': ... {'es': 6, 'hi': 2, 'ru': 4, 'ta': 1, 'bn': 2, ... {}
2018-05-03 {'es': 40, 'da': 1, 'pt': 5, 'ar': 13, 'fa': 1... {'es': 3, 'fa': 8, 'zh-tw': 1, 'pnt': 1, 'fr':... {}
2018-05-04 {'ru': 17, 'qu': 1, 'ceb': 1, 'sv': 112, 'pt':... {'es': 2, 'de': 8, 'pt': 1, 'rm': 1, 'ur': 1, ... {}
2018-05-05 {'de': 49, 'es': 31, 'vi': 3, 'hi': 7, 'pt': 9... {'de': 7, 'pt': 1, 'fi': 1, 'es': 2, 'fa': 3, ... {}

100 rows × 3 columns

revperdaylang.head(100)
all reverted reverted_rate
2016-12-31 {} {} {}
2017-01-01 {'en': 2} {'en': 1} {}
2017-01-02 {} {} {}
2017-01-03 {'en': 5} {'en': 2} {}
2017-01-04 {'en': 12} {'en': 1} {}
2017-01-05 {'en': 5} {} {}
2017-01-06 {'en': 4} {'en': 2} {}
2017-01-07 {} {} {}
2017-01-08 {} {} {}
2017-01-09 {'en': 1} {} {}
2017-01-10 {'en': 1} {} {}
2017-01-11 {'en': 4} {} {}
2017-01-12 {'en': 3} {'en': 1} {}
2017-01-13 {'en': 5} {'en': 3} {}
2017-01-14 {} {} {}
2017-01-15 {'en': 2} {} {}
2017-01-16 {} {} {}
2017-01-17 {} {} {}
2017-01-18 {} {} {}
2017-01-19 {'en': 19} {'en': 6} {}
2017-01-20 {'en': 5} {} {}
2017-01-21 {} {} {}
2017-01-22 {} {} {}
2017-01-23 {'en': 7} {'en': 6} {}
2017-01-24 {'en': 13} {'en': 9} {}
2017-01-25 {'en': 4} {'en': 1} {}
2017-01-26 {'en': 11} {'en': 10} {}
2017-01-27 {'en': 10} {'en': 1} {}
2017-01-28 {'en': 1} {'en': 1} {}
2017-01-29 {} {} {}
... ... ... ...
2017-03-11 {'he': 11, 'ru': 82, 'ca': 55, 'id': 1, 'hr': 1} {'ru': 4} {}
2017-03-12 {'he': 17, 'ru': 29, 'ca': 54, 'ar': 1, 'hr': 1} {'ru': 2} {}
2017-03-13 {'he': 27, 'ru': 49, 'hr': 5, 'ca': 17} {'ru': 4} {}
2017-03-14 {'ru': 64, 'he': 13, 'ca': 4} {'ru': 7} {}
2017-03-15 {'ru': 78, 'he': 16, 'ca': 3} {'ru': 6} {}
2017-03-16 {'ru': 30, 'he': 15, 'ca': 1} {'ru': 3} {}
2017-03-17 {'he': 13, 'ru': 24, 'ca': 11, 'en': 1} {} {}
2017-03-18 {'en': 2, 'ru': 39, 'he': 16, 'ca': 10, 'ar': 2} {'ru': 5, 'he': 1} {}
2017-03-19 {'ru': 98, 'he': 13, 'ar': 1, 'ca': 22} {'ru': 34} {}
2017-03-20 {'ru': 100, 'ar': 1, 'ca': 22, 'he': 43} {'ru': 27, 'ca': 1} {}
2017-03-21 {'he': 35, 'ru': 28, 'en': 1, 'ca': 10} {'ru': 4} {}
2017-03-22 {'ru': 51, 'he': 13, 'ca': 1, 'ar': 8} {'ru': 9} {}
2017-03-23 {'ru': 40, 'he': 173, 'ca': 17} {'ru': 5} {}
2017-03-24 {'he': 386, 'ru': 182, 'ca': 17} {'he': 1, 'ru': 3} {}
2017-03-25 {'he': 210, 'en': 12, 'ru': 54, 'ca': 10} {'he': 1, 'ru': 1} {}
2017-03-26 {'he': 65, 'ru': 22, 'ca': 12, 'en': 1} {'ru': 2} {}
2017-03-27 {'he': 19, 'ru': 17, 'ca': 11} {'ru': 2, 'he': 1} {}
2017-03-28 {'he': 28, 'ru': 81, 'ca': 7} {'ru': 6} {}
2017-03-29 {'he': 19, 'ru': 42, 'ca': 2} {'ru': 5} {}
2017-03-30 {'ru': 33, 'he': 19, 'unknown': 2, 'hr': 24} {'unknown': 2, 'ru': 2} {}
2017-03-31 {'ru': 26, 'he': 20, 'hr': 2, 'ca': 13, 'ar': 1} {'ru': 1, 'he': 2} {}
2017-04-01 {'ru': 14, 'he': 31, 'ca': 16} {'ru': 1} {}
2017-04-02 {'he': 28, 'ru': 65, 'ca': 1} {'ru': 5} {}
2017-04-03 {'he': 10, 'ru': 49, 'ca': 6} {'ru': 7, 'ca': 4} {}
2017-04-04 {'ru': 14, 'ca': 5, 'he': 8} {'ru': 3} {}
2017-04-05 {'he': 23, 'ru': 26, 'ca': 8} {'ru': 2, 'ca': 2} {}
2017-04-06 {'ru': 38, 'he': 30, 'ca': 10} {} {}
2017-04-07 {'ru': 69, 'he': 15} {'ru': 3} {}
2017-04-08 {'ru': 33, 'en': 5, 'he': 18, 'ca': 10} {} {}
2017-04-09 {'he': 29, 'ru': 33, 'ar': 2, 'ca': 4} {'ru': 1} {}

100 rows × 3 columns

# check result
revperday.tail(150)
all reverted reverted_rate reverters
2017-12-07 293 31 0.105802 {'ديفيد عادل وهبة خليل 2': 9, 'Wostr': 1, 'Val...
2017-12-08 377 19 0.050398 {'Andreasmperu': 1, 'YMS': 3, 'Matěj Suchánek'...
2017-12-09 678 29 0.042773 {'ValterVB': 3, 'Strakhov': 1, 'ديفيد عادل وهب...
2017-12-10 586 37 0.063140 {'ديفيد عادل وهبة خليل 2': 17, 'FallingGravity...
2017-12-11 416 46 0.110577 {'ديفيد عادل وهبة خليل 2': 9, '45.248.118.0': ...
2017-12-12 456 46 0.100877 {'ديفيد عادل وهبة خليل 2': 3, 'YMS': 17, 'Lads...
2017-12-13 411 41 0.099757 {'ديفيد عادل وهبة خليل 2': 12, 'YMS': 9, 'Lads...
2017-12-14 320 23 0.071875 {'Asqueladd': 1, 'ديفيد عادل وهبة خليل 2': 1, ...
2017-12-15 317 34 0.107256 {'本日晴天': 1, 'ديفيد عادل وهبة خليل 2': 4, 'YMS'...
2017-12-16 352 31 0.088068 {'-revi': 1, 'Pasleim': 8, 'NicoScribe': 5, 'د...
2017-12-17 539 34 0.063080 {'93.70.17.243': 1, 'ديفيد عادل وهبة خليل 2': ...
2017-12-18 562 35 0.062278 {'Andreasmperu': 1, 'Irn': 1, 'Rojelio': 2, 'د...
2017-12-19 336 16 0.047619 {'Ladsgroup': 1, 'Rojelio': 5, '91.253.136.183...
2017-12-20 333 34 0.102102 {'Hiàn': 2, 'ديفيد عادل وهبة خليل 2': 9, 'YMS'...
2017-12-21 373 28 0.075067 {'ديفيد عادل وهبة خليل 2': 4, 'Mattythewhite':...
2017-12-22 394 56 0.142132 {'Andres Monge': 2, 'Ladsgroup': 25, 'Pasleim'...
2017-12-23 423 42 0.099291 {'Ladsgroup': 5, 'ValterVB': 1, '82.208.100.20...
2017-12-24 437 47 0.107551 {'ديفيد عادل وهبة خليل 2': 10, 'NicoScribe': 1...
2017-12-25 472 43 0.091102 {'YussufHr123': 1, '79.31.244.157': 1, 'ديفيد ...
2017-12-26 711 42 0.059072 {'Asqueladd': 1, 'Ladsgroup': 6, 'Auaan': 1, '...
2017-12-27 574 36 0.062718 {'109.43.0.5': 1, 'YMS': 7, 'Johnny Paes': 1, ...
2017-12-28 696 47 0.067529 {'YMS': 12, 'ديفيد عادل وهبة خليل 2': 3, 'HaeB...
2017-12-29 598 52 0.086957 {'186.188.248.60': 1, 'Horcrux92': 1, 'ValterV...
2017-12-30 448 47 0.104911 {'علاء': 12, 'NicoScribe': 1, 'Succu': 2, 'ديف...
2017-12-31 651 79 0.121352 {'ValterVB': 6, 'Prefall': 4, '190.183.60.71':...
2018-01-01 756 209 0.276455 {'ValterVB': 2, '93.218.125.215': 1, 'Irn': 1,...
2018-01-02 857 41 0.047841 {'ValterVB': 8, 'Andreasmperu': 5, 'Ladsgroup'...
2018-01-03 533 30 0.056285 {'Davidpar': 3, 'ValterVB': 4, '188.168.35.22'...
2018-01-04 538 32 0.059480 {'YMS': 8, 'ديفيد عادل وهبة خليل 2': 7, 'Rachm...
2018-01-05 413 32 0.077482 {'DavideCarli2000': 1, 'Drüfft': 3, 'ديفيد عاد...
... ... ... ... ...
2018-04-06 700 24 0.034286 {'Epìdosis': 1, 'ديفيد عادل وهبة خليل 2': 2, '...
2018-04-07 648 34 0.052469 {'ديفيد عادل وهبة خليل 2': 5, 'HaeB': 1, 'YMS'...
2018-04-08 863 36 0.041715 {'Ahoerstemeier': 1, 'ديفيد عادل وهبة خليل 2':...
2018-04-09 564 41 0.072695 {'Mahir256': 2, 'Afaz': 2, '175.157.69.109': 1...
2018-04-10 354 49 0.138418 {'47.29.255.63': 1, 'Ladsgroup': 5, 'ValterVB'...
2018-04-11 365 33 0.090411 {'Mahir256': 1, 'JRHcst': 1, 'Lucywood': 1, '2...
2018-04-12 451 43 0.095344 {'Wikidelo': 1, 'ديفيد عادل وهبة خليل 2': 8, '...
2018-04-13 415 41 0.098795 {'Spinster': 2, 'Hiàn': 1, 'Pasleim': 5, 'NewD...
2018-04-14 637 34 0.053375 {'24.122.184.139': 1, 'LittleWink': 1, 'Kalend...
2018-04-15 462 27 0.058442 {'Esteban16': 1, 'Ladsgroup': 4, 'ديفيد عادل و...
2018-04-16 358 28 0.078212 {'YMS': 2, 'Kam Solusar': 3, 'Jklamo': 1, 'ديف...
2018-04-17 463 48 0.103672 {'Esteban16': 5, 'Mahir256': 1, 'Kalendar': 6,...
2018-04-18 461 47 0.101952 {'Wikidelo': 1, 'YMS': 13, 'HakanIST': 1, 'Mah...
2018-04-19 356 53 0.148876 {'188.211.183.138': 1, 'Ladsgroup': 3, 'HakanI...
2018-04-20 500 38 0.076000 {'Matěj Suchánek': 1, 'Ladsgroup': 3, 'B.O.B. ...
2018-04-21 736 29 0.039402 {'Mbch331': 1, 'Pasleim': 4, 'FallingGravity':...
2018-04-22 609 34 0.055829 {'Sintakso': 1, 'Ladsgroup': 5, 'ValterVB': 6,...
2018-04-23 453 45 0.099338 {'YMS': 8, 'Shinnin': 1, 'Jklamo': 1, 'ASammou...
2018-04-24 382 28 0.073298 {'Afaz': 1, 'Pasleim': 4, 'Ladsgroup': 3, 'YMS...
2018-04-25 466 49 0.105150 {'Ladsgroup': 4, 'Pasleim': 7, '2405:205:A001:...
2018-04-26 458 38 0.082969 {'YMS': 9, 'Ladsgroup': 5, 'Kalendar': 4, 'ديف...
2018-04-27 305 27 0.088525 {'Esteban16': 1, 'Ladsgroup': 2, 'ASammour': 5...
2018-04-28 335 35 0.104478 {'Mahir256': 1, 'Wurgl': 2, 'ValterVB': 1, 'YM...
2018-04-29 538 33 0.061338 {'106.181.104.75': 1, 'ShockD': 2, '1997kB': 3...
2018-04-30 344 39 0.113372 {'YMS': 16, 'Ladsgroup': 2, '41.223.179.36': 1...
2018-05-01 451 64 0.141907 {'Dimarm': 1, 'YMS': 19, 'Ladsgroup': 7, 'ديفي...
2018-05-02 306 42 0.137255 {'YMS': 10, 'ديفيد عادل وهبة خليل 2': 5, 'RHRa...
2018-05-03 235 34 0.144681 {'YMS': 5, 'Ladsgroup': 7, 'Shizhao': 1, 'Pasl...
2018-05-04 405 39 0.096296 {'Andreasmperu': 1, 'YMS': 10, 'Pasleim': 6, '...
2018-05-05 400 42 0.105000 {'Kam Solusar': 4, 'Spinster': 1, 'Shinnin': 3...

150 rows × 4 columns

# what happened on January 1, 2018?
revperday.loc['2018-01-01']['reverters']
defaultdict(int,
            {'109.248.242.238': 1,
             '85.76.66.24': 1,
             '93.218.125.215': 1,
             'Andreasmperu': 47,
             'Bankster': 1,
             'DmitTrix': 1,
             'HernánDávalos13': 1,
             'Irn': 1,
             'Kam Solusar': 3,
             'Ladsgroup': 2,
             'Mbch331': 1,
             'NicoScribe': 2,
             'Pasleim': 5,
             'Tractopelle-jaune': 94,
             'ValterVB': 2,
             'YMS': 34,
             'ديفيد عادل وهبة خليل 2': 2,
             'فرهنگ2016': 1,
             'مصعب': 9})

174 edits by a single IP on January 1, many or most reverted: https://www.wikidata.org/w/index.php?limit=250&title=Special%3AContributions&contribs=user&target=191.179.171.31&namespace=&tagfilter=&start=2018-01-01&end=2018-01-01 https://www.wikidata.org/wiki/User_talk:191.179.171.31 : "What is your rationale behind shortening all these descriptions? While in some cases these short descriptions are equally good as the long ones or actually better because you drop unnecessary stuff, many appear crippled to me."

# plot edits vs. reverts in absolute terms
fig, ax = plt.subplots(dpi=300)
cols = ['all','reverted']
colm2colr = { 
    'reverted': 'red'
}
revperday[cols].plot(ax=ax, color=map(colm2colr.get, cols))
ax.set_title('Mobile app edits on Wikidata, total vs. reverted')

pfeilstil = dict(facecolor='black', shrink=0.01, width=0.8, headwidth=6)
plt.annotate("description\nediting\navailable in\nalpha only", xycoords='data', xy=('2017-01-15',45), xytext=('2017-01-07',210), ha='center', fontsize = 5, arrowprops=pfeilstil)
plt.annotate("rolled out\nwith beta app\n(ru, he, ca)", xycoords='data', xy=('2017-02-09',100), xytext=('2017-01-28',430), ha='center', fontsize = 5, arrowprops=pfeilstil)
plt.annotate("rolled out\nin production\n(ru, he, ca)", xycoords='data', xy=('2017-02-27',150), xytext=('2017-02-27',550), ha='center', fontsize = 5, arrowprops=pfeilstil)
plt.annotate("March 24:\n371 he edits\nby a single user", xycoords='data', xy=('2017-03-14',650), xytext=('2017-01-20',900), ha='center', fontsize = 5, arrowprops=pfeilstil)
# cf. https://www.wikidata.org/w/index.php?title=Special:Contributions/MathKnight-at-TAU&offset=&limit=1000&target=MathKnight-at-TAU
plt.annotate("rolled out\nin production\nfor more\nlanguages", xycoords='data', xy=('2017-04-24',350), xytext=('2017-04-06',750), ha='center', fontsize = 5, arrowprops=pfeilstil)
plt.annotate("rolled out\nin production\nfor all\nexcept English", xycoords='data', xy=('2017-07-05',320), xytext=('2017-05-28',1000), ha='center', fontsize = 5, arrowprops=pfeilstil)
plt.annotate("174\ncontroversial\nedits by\na single IP", xycoords='data', xy=('2017-12-28',200), xytext=('2017-10-05',150), ha='center', fontsize = 5, arrowprops=pfeilstil)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/srv/paws/lib/python3.6/site-packages/IPython/core/formatters.py in __call__(self, obj)
    700                 type_pprinters=self.type_printers,
    701                 deferred_pprinters=self.deferred_printers)
--> 702             printer.pretty(obj)
    703             printer.flush()
    704             return stream.getvalue()

/srv/paws/lib/python3.6/site-packages/IPython/lib/pretty.py in pretty(self, obj)
    393                             if callable(meth):
    394                                 return meth(obj, self, cycle)
--> 395             return _default_pprint(obj, self, cycle)
    396         finally:
    397             self.end_group()

/srv/paws/lib/python3.6/site-packages/IPython/lib/pretty.py in _default_pprint(obj, p, cycle)
    508     if _safe_getattr(klass, '__repr__', None) is not object.__repr__:
    509         # A user-provided repr. Find newlines and replace them with p.break_()
--> 510         _repr_pprint(obj, p, cycle)
    511         return
    512     p.begin_group(1, '<')

/srv/paws/lib/python3.6/site-packages/IPython/lib/pretty.py in _repr_pprint(obj, p, cycle)
    699     """A pprint that just redirects to the normal repr function."""
    700     # Find newlines and replace them with p.break_()
--> 701     output = repr(obj)
    702     for idx,output_line in enumerate(output.splitlines()):
    703         if idx:

/srv/paws/lib/python3.6/site-packages/matplotlib/text.py in __repr__(self)
    132 
    133     def __repr__(self):
--> 134         return "Text(%g,%g,%s)" % (self._x, self._y, repr(self._text))
    135 
    136     def __init__(self,

TypeError: must be real number, not str
revrateperday = revperday['reverted'] / revperday['all']
revrateperday.tail()
2018-05-01    0.141907
2018-05-02    0.137255
2018-05-03    0.144681
2018-05-04    0.096296
2018-05-05    0.105000
Freq: D, dtype: float64
daterange2 =  pd.date_range(start='2017-02-10', end='2018-05-05', freq='D')
revrateperday.loc[daterange2]
2017-02-10    0.031008
2017-02-11    0.000000
2017-02-12    0.166667
2017-02-13    0.045455
2017-02-14    0.264706
2017-02-15    0.000000
2017-02-16    0.000000
2017-02-17    0.000000
2017-02-18    0.000000
2017-02-19    0.000000
2017-02-20    0.000000
2017-02-21    0.538462
2017-02-22    0.166667
2017-02-23    0.000000
2017-02-24    0.000000
2017-02-25    0.000000
2017-02-26    0.000000
2017-02-27    0.083333
2017-02-28    0.149254
2017-03-01    0.036036
2017-03-02    0.062992
2017-03-03    0.008264
2017-03-04    0.007752
2017-03-05    0.014286
2017-03-06    0.067729
2017-03-07    0.035503
2017-03-08    0.072115
2017-03-09    0.008547
2017-03-10    0.025641
2017-03-11    0.026667
                ...   
2018-04-06    0.034286
2018-04-07    0.052469
2018-04-08    0.041715
2018-04-09    0.072695
2018-04-10    0.138418
2018-04-11    0.090411
2018-04-12    0.095344
2018-04-13    0.098795
2018-04-14    0.053375
2018-04-15    0.058442
2018-04-16    0.078212
2018-04-17    0.103672
2018-04-18    0.101952
2018-04-19    0.148876
2018-04-20    0.076000
2018-04-21    0.039402
2018-04-22    0.055829
2018-04-23    0.099338
2018-04-24    0.073298
2018-04-25    0.105150
2018-04-26    0.082969
2018-04-27    0.088525
2018-04-28    0.104478
2018-04-29    0.061338
2018-04-30    0.113372
2018-05-01    0.141907
2018-05-02    0.137255
2018-05-03    0.144681
2018-05-04    0.096296
2018-05-05    0.105000
Freq: D, Length: 450, dtype: float64
fig, ax = plt.subplots(dpi=100)
revrateperday.loc[daterange2].plot(ax=ax)
ax.set_title('revert rate for mobile app edits on Wikidata')
vals = ax.get_yticks()
ax.set_yticklabels(['{:3.0f}%'.format(y*100) for y in vals])
[Text(0,0,'-10%'),
 Text(0,0,'  0%'),
 Text(0,0,' 10%'),
 Text(0,0,' 20%'),
 Text(0,0,' 30%'),
 Text(0,0,' 40%'),
 Text(0,0,' 50%'),
 Text(0,0,' 60%')]
# calculate overall reverted rate during timespan
overallapprevertrate = revperday.loc[daterange2][['reverted']].values.sum() / revperday.loc[daterange2][['all']].values.sum()
print(overallapprevertrate)
print(revperday.loc[daterange2][['all']].values.sum())
0.0852129582975192
168695
# calculate overall reverted rate per language during timespan

# sum over all languages that occurred
langs = set()
allperlang = collections.Counter()
revperlang = collections.Counter()

for i in revperdaylang.index:
    langs = langs | set(revperdaylang['all'][i].keys())
    allperlang = allperlang + collections.Counter(revperdaylang['all'][i])
    revperlang = revperlang + collections.Counter(revperdaylang['reverted'][i])
    
# combine into one dataframe
try:
    del(perlang)
except NameError:
    pass
perlang = pd.DataFrame(index=langs, columns = ['all', 'reverted', 'revert_rate'])
perlang[['all', 'reverted']] = perlang[['all', 'reverted']].fillna(0)
perlang[['revert_rate']] = perlang[['revert_rate']].fillna(np.NaN)

for lang in langs:
    perlang.loc[lang,'all'] = allperlang[lang]
    perlang.loc[lang,'reverted'] = revperlang[lang]
    if allperlang[lang] > 0:
        perlang.loc[lang,'revert_rate'] = revperlang[lang] / allperlang[lang]
# result
perlang
all reverted revert_rate
5 3 0.600000
ha 6 1 0.166667
dsb 2 2 1.000000
mr 486 89 0.183128
sh 49 8 0.163265
de 19554 1178 0.060243
dz 2 0 0.000000
mwl 1 1 1.000000
hu 965 69 0.071503
sk 2504 14 0.005591
gan 2 1 0.500000
ang 14 7 0.500000
kl 1 1 1.000000
chr 2 1 0.500000
zh-hant 691 51 0.073806
zh-hk 12 0 0.000000
mrj 1 1 1.000000
zh-hans 916 47 0.051310
yo 7 4 0.571429
sn 2 1 0.500000
oc 8 1 0.125000
krc 1 1 1.000000
ur 355 85 0.239437
ay 3 2 0.666667
unknown 47 27 0.574468
cdo 93 1 0.010753
sr 575 85 0.147826
et 54 6 0.111111
si 102 32 0.313725
pa 224 17 0.075893
... ... ... ...
rw 1 0 0.000000
sa 32 16 0.500000
ps 241 12 0.049793
azb 9 2 0.222222
ko 1950 138 0.070769
ku 22 3 0.136364
am 65 18 0.276923
ru 13468 1200 0.089100
min 1 1 1.000000
cy 13 2 0.153846
tcy 6 1 0.166667
uk 844 81 0.095972
gu 178 51 0.286517
lb 76 0 0.000000
fi 3270 132 0.040367
mai 26 4 0.153846
arz 29 10 0.344828
lo 72 1 0.013889
it 13701 795 0.058025
srn 1 1 1.000000
zh-tw 50 5 0.100000
nso 2 2 1.000000
tet 5 5 1.000000
vls 2 0 0.000000
az 639 75 0.117371
mk 30 6 0.200000
vep 1 1 1.000000
sl 53 16 0.301887
wuu 10 1 0.100000
or 42 6 0.142857

212 rows × 3 columns

# revert rate by language, largest to smallest
perlang.sort_values('all',ascending=False)
all reverted revert_rate
es 20652 2047 0.099119
de 19554 1178 0.060243
it 13701 795 0.058025
ru 13468 1200 0.089100
sv 10877 116 0.010665
ar 9893 1702 0.172041
he 8368 149 0.017806
fr 7212 774 0.107321
fa 6167 1105 0.179180
pt 5840 828 0.141781
cs 5150 125 0.024272
ja 4566 176 0.038546
fi 3270 132 0.040367
pl 3165 197 0.062243
nl 2806 131 0.046686
id 2762 255 0.092324
sk 2504 14 0.005591
hi 2287 569 0.248798
ca 2071 97 0.046837
ko 1950 138 0.070769
bn 1866 202 0.108253
vi 1450 136 0.093793
lv 1202 7 0.005824
ml 1034 82 0.079304
gl 1004 7 0.006972
hu 965 69 0.071503
zh-hans 916 47 0.051310
uk 844 81 0.095972
zh-hant 691 51 0.073806
az 639 75 0.117371
... ... ... ...
kl 1 1 1.000000
mrj 1 1 1.000000
vep 1 1 1.000000
pam 1 0 0.000000
mwl 1 1 1.000000
min 1 1 1.000000
srn 1 1 1.000000
pag 1 0 0.000000
rue 1 0 0.000000
bi 1 1 1.000000
ba 1 1 1.000000
mhr 1 1 1.000000
mg 1 0 0.000000
pap 1 1 1.000000
na 1 1 1.000000
lez 1 1 1.000000
ia 1 1 1.000000
bxr 1 0 0.000000
kbp 1 0 0.000000
ak 1 1 1.000000
krc 1 1 1.000000
gom 1 0 0.000000
kw 1 0 0.000000
pi 1 0 0.000000
gv 1 1 1.000000
fur 1 0 0.000000
mt 1 0 0.000000
cr 1 1 1.000000
rw 1 0 0.000000
nv 1 1 1.000000

212 rows × 3 columns

%%time
# calculate revert rate for anon vs logged-in, for one week of data
!date

# initialize dataframes to count reverts per day:
daterange3 =  pd.date_range(start='2017-07-25', end='2017-07-31', freq='D')

anonedits = 0
anonreverted = 0
loginedits = 0
loginreverted = 0

# count reverts per condition:
for rev in appedits:
    day = pd.to_datetime(rev[1][:8].decode())
    
    if day in daterange:
        
        isanon = (rev[4] == 0) 
        
        if isanon:
            anonedits +=1
        else:
            loginedits +=1
               
        rev_id = rev[0]
        # from http://paws-public.wmflabs.org/paws-public/User:EpochFail/editquality/ipython/reverted_detection_demo.ipynb :
        try:
            _, reverted, reverted_to = mwreverts.api.check(
                session, rev_id, radius=5,  # most reverts happen within 5 edits
                window=48*60*60,  # 2 days
                rvprop={'user', 'ids'})  # Some properties we may make use of later
        except RuntimeError as e:
            sys.stderr.write(str(e))
            continue
        
    
        
        if reverted:
            if isanon:
                anonreverted +=1
            else:
                loginreverted +=1
                
Mon Aug 28 22:57:14 UTC 2017
print(anonreverted/anonedits)
print(loginreverted/loginedits)
0.14908366533864542
0.021846173694282583

Calculate revert rate for all description edits (including non-app edits, excluding bots)

# see https://paws.wmflabs.org/paws/user/HaeB/notebooks/Mobile%20app%20edits%20on%20Wikidata.ipynb#Calculate-revert-rate-for-all-description-edits-(including-non-app-edits,-excluding-bots)

Scratchpad / debugging

# test revert detection, restricting to a smaller list that includes some reverted ones
# cf. http://paws-public.wmflabs.org/paws-public/User:EpochFail/editquality/ipython/reverted_detection_demo.ipynb :
for rev in appedits:
    if rev[1][:8] == b'20170628':        
        rev_id = rev[0]
        # from http://paws-public.wmflabs.org/paws-public/User:EpochFail/editquality/ipython/reverted_detection_demo.ipynb :
        try:
            _, reverted, reverted_to = mwreverts.api.check(
                session, rev_id, radius=5,  # most reverts within 5 edits
                window=48*60*60,  # 2 days
                rvprop={'user', 'ids'})  # Some properties we'll make use of
        except RuntimeError as e:
            sys.stderr.write(str(e))
            continue
        
        # leave out special cases of self-reverts and reverts that were re-reverted

        if reverted:
            print('https://www.wikidata.org/w/index.php?diff=' + str(rev[0]) + ' by ' + rev[3].decode() + ' was reverted by '+ reverted.reverting['user'])
        else:
            print('https://www.wikidata.org/w/index.php?diff=' + str(rev[0]) + ' by ' + rev[3].decode() + ' was not reverted')
https://www.wikidata.org/w/index.php?diff=508508149 by Shahzaib62342 was not reverted
https://www.wikidata.org/w/index.php?diff=508508473 by Shahzaib62342 was not reverted
https://www.wikidata.org/w/index.php?diff=508517236 by 14.171.151.31 was not reverted
https://www.wikidata.org/w/index.php?diff=508532870 by 188.113.189.54 was not reverted
https://www.wikidata.org/w/index.php?diff=508539543 by 27.77.81.15 was reverted by ValterVB
https://www.wikidata.org/w/index.php?diff=508567228 by 2001:16A2:89E7:6900:A4C8:E057:90CC:9C4 was not reverted
https://www.wikidata.org/w/index.php?diff=508568155 by 2001:16A2:89E7:6900:A4C8:E057:90CC:9C4 was not reverted
https://www.wikidata.org/w/index.php?diff=508569526 by 陳啟章 was not reverted
https://www.wikidata.org/w/index.php?diff=508579086 by 113.210.124.81 was not reverted
https://www.wikidata.org/w/index.php?diff=508583506 by ЯМАДА Таро was not reverted
https://www.wikidata.org/w/index.php?diff=508586556 by 37.40.23.88 was not reverted
https://www.wikidata.org/w/index.php?diff=508591734 by 2405:204:8383:5CC9:0:0:14C8:80AD was reverted by Epìdosis
https://www.wikidata.org/w/index.php?diff=508600688 by 109.242.95.160 was not reverted
https://www.wikidata.org/w/index.php?diff=508608640 by Valdep was not reverted
https://www.wikidata.org/w/index.php?diff=508616877 by 188.55.228.26 was not reverted
https://www.wikidata.org/w/index.php?diff=508637050 by GTRus was not reverted
https://www.wikidata.org/w/index.php?diff=508637203 by GTRus was not reverted
https://www.wikidata.org/w/index.php?diff=508637405 by GTRus was not reverted
https://www.wikidata.org/w/index.php?diff=508638387 by 185.160.104.34 was not reverted
https://www.wikidata.org/w/index.php?diff=508640841 by Jimjason123 was not reverted
https://www.wikidata.org/w/index.php?diff=508641272 by Jimjason123 was not reverted
https://www.wikidata.org/w/index.php?diff=508649077 by GTRus was not reverted
https://www.wikidata.org/w/index.php?diff=508650033 by Shahzaib62342 was not reverted
https://www.wikidata.org/w/index.php?diff=508665468 by 106.76.2.112 was not reverted
https://www.wikidata.org/w/index.php?diff=508677862 by Ududsu was not reverted
https://www.wikidata.org/w/index.php?diff=508681367 by Mrs markiza was not reverted
https://www.wikidata.org/w/index.php?diff=508684931 by Mrs markiza was not reverted
https://www.wikidata.org/w/index.php?diff=508685676 by Mrs markiza was not reverted
https://www.wikidata.org/w/index.php?diff=508689178 by Mrs markiza was not reverted
https://www.wikidata.org/w/index.php?diff=508691541 by 185.54.167.121 was not reverted
https://www.wikidata.org/w/index.php?diff=508692407 by 114.125.19.175 was not reverted
https://www.wikidata.org/w/index.php?diff=508705724 by 85.76.7.161 was not reverted
https://www.wikidata.org/w/index.php?diff=508711631 by Mrs markiza was not reverted
https://www.wikidata.org/w/index.php?diff=508711891 by Mrs markiza was not reverted
https://www.wikidata.org/w/index.php?diff=508712441 by Mrs markiza was not reverted
https://www.wikidata.org/w/index.php?diff=508712877 by Mrs markiza was not reverted
https://www.wikidata.org/w/index.php?diff=508713113 by Mrs markiza was not reverted
https://www.wikidata.org/w/index.php?diff=508713727 by Mrs markiza was not reverted
https://www.wikidata.org/w/index.php?diff=508714257 by Mrs markiza was not reverted
https://www.wikidata.org/w/index.php?diff=508715758 by 83.9.80.112 was not reverted
https://www.wikidata.org/w/index.php?diff=508729622 by Mrs markiza was not reverted
https://www.wikidata.org/w/index.php?diff=508733697 by 5.197.243.111 was not reverted
https://www.wikidata.org/w/index.php?diff=508743609 by Frahbil was not reverted
https://www.wikidata.org/w/index.php?diff=508759321 by 77.244.119.56 was not reverted
https://www.wikidata.org/w/index.php?diff=508774942 by 87.207.96.32 was not reverted
https://www.wikidata.org/w/index.php?diff=508775899 by 178.137.75.242 was not reverted
https://www.wikidata.org/w/index.php?diff=508776510 by 125.161.221.78 was not reverted
https://www.wikidata.org/w/index.php?diff=508780193 by 178.137.75.242 was not reverted
https://www.wikidata.org/w/index.php?diff=508781061 by 5.119.247.215 was not reverted
https://www.wikidata.org/w/index.php?diff=508797227 by 149.86.240.162 was not reverted
https://www.wikidata.org/w/index.php?diff=508798983 by 95.131.169.250 was not reverted
https://www.wikidata.org/w/index.php?diff=508799225 by 95.131.169.250 was not reverted
https://www.wikidata.org/w/index.php?diff=508799242 by 49.149.2.49 was not reverted
https://www.wikidata.org/w/index.php?diff=508800167 by 49.149.2.49 was not reverted
https://www.wikidata.org/w/index.php?diff=508802569 by Диас Абуталип was not reverted
https://www.wikidata.org/w/index.php?diff=508803227 by 94.243.70.197 was not reverted
https://www.wikidata.org/w/index.php?diff=508818628 by Tuguldurerdene was not reverted
https://www.wikidata.org/w/index.php?diff=508819564 by Tuguldurerdene was not reverted
https://www.wikidata.org/w/index.php?diff=508822756 by Tuguldurerdene was not reverted
https://www.wikidata.org/w/index.php?diff=508827308 by Seyedemran was not reverted
https://www.wikidata.org/w/index.php?diff=508830404 by 129.45.48.18 was not reverted
https://www.wikidata.org/w/index.php?diff=508851433 by 194.151.204.24 was not reverted
https://www.wikidata.org/w/index.php?diff=508856459 by 46.211.67.89 was not reverted
https://www.wikidata.org/w/index.php?diff=508866494 by Biegel was not reverted
https://www.wikidata.org/w/index.php?diff=508873842 by 217.65.199.88 was reverted by ديفيد عادل وهبة خليل 2
https://www.wikidata.org/w/index.php?diff=508878672 by 41.142.168.218 was not reverted
https://www.wikidata.org/w/index.php?diff=508889366 by Mr. Andro was not reverted
https://www.wikidata.org/w/index.php?diff=508890010 by VitVit was not reverted
https://www.wikidata.org/w/index.php?diff=508894161 by Xosé was not reverted
https://www.wikidata.org/w/index.php?diff=508896121 by 112.209.243.39 was not reverted
https://www.wikidata.org/w/index.php?diff=508896137 by 2405:204:9317:355D:0:0:1AF4:D8AC was reverted by YMS
https://www.wikidata.org/w/index.php?diff=508899474 by 2405:204:5605:A349:DB59:FB6C:63BE:1CF8 was not reverted
https://www.wikidata.org/w/index.php?diff=508900928 by 2405:204:5605:A349:DB59:FB6C:63BE:1CF8 was not reverted
https://www.wikidata.org/w/index.php?diff=508902662 by Oba7da was not reverted
https://www.wikidata.org/w/index.php?diff=508910564 by Monthasawang was not reverted
https://www.wikidata.org/w/index.php?diff=508911058 by 217.72.82.156 was not reverted
https://www.wikidata.org/w/index.php?diff=508911256 by 217.72.82.156 was not reverted
https://www.wikidata.org/w/index.php?diff=508912524 by Guy.binyamin was not reverted
https://www.wikidata.org/w/index.php?diff=508913273 by 178.127.201.216 was not reverted
https://www.wikidata.org/w/index.php?diff=508913827 by 2405:204:5605:A349:DB59:FB6C:63BE:1CF8 was not reverted
https://www.wikidata.org/w/index.php?diff=508915480 by 217.72.82.156 was not reverted
https://www.wikidata.org/w/index.php?diff=508915898 by 217.72.82.156 was not reverted
https://www.wikidata.org/w/index.php?diff=508919342 by 112.215.244.112 was not reverted
https://www.wikidata.org/w/index.php?diff=508920653 by 217.72.82.156 was not reverted
https://www.wikidata.org/w/index.php?diff=508921926 by 81.26.205.70 was not reverted
https://www.wikidata.org/w/index.php?diff=508923388 by Arnel1234 was not reverted
https://www.wikidata.org/w/index.php?diff=508925416 by Yhteistyössä was not reverted
https://www.wikidata.org/w/index.php?diff=508926300 by Yhteistyössä was not reverted
https://www.wikidata.org/w/index.php?diff=508935268 by AshYari was not reverted
https://www.wikidata.org/w/index.php?diff=508935996 by Arnel1234 was not reverted
https://www.wikidata.org/w/index.php?diff=508936169 by 120.29.65.3 was not reverted
https://www.wikidata.org/w/index.php?diff=508937073 by Arnel1234 was not reverted
https://www.wikidata.org/w/index.php?diff=508944625 by 62.176.119.2 was not reverted
https://www.wikidata.org/w/index.php?diff=508948690 by 2405:204:8289:A653:0:0:13D7:80B0 was reverted by Jared Preston
https://www.wikidata.org/w/index.php?diff=508949624 by 27.97.215.12 was reverted by Florentyna
https://www.wikidata.org/w/index.php?diff=508958654 by 95.86.80.129 was not reverted
https://www.wikidata.org/w/index.php?diff=508968346 by Mrs markiza was not reverted
https://www.wikidata.org/w/index.php?diff=508968818 by MathKnight-at-TAU was not reverted
https://www.wikidata.org/w/index.php?diff=508981814 by 213.57.198.105 was not reverted
https://www.wikidata.org/w/index.php?diff=508984943 by Aymoni was not reverted
https://www.wikidata.org/w/index.php?diff=508986514 by Aymoni was not reverted
https://www.wikidata.org/w/index.php?diff=508989587 by 207.204.64.130 was reverted by YMS
https://www.wikidata.org/w/index.php?diff=508991276 by Biegel was not reverted
https://www.wikidata.org/w/index.php?diff=508991340 by Biegel was not reverted
https://www.wikidata.org/w/index.php?diff=508991790 by 111.92.27.17 was not reverted
https://www.wikidata.org/w/index.php?diff=508992589 by Amiramore was not reverted
https://www.wikidata.org/w/index.php?diff=508994033 by 185.79.102.18 was not reverted
https://www.wikidata.org/w/index.php?diff=508998882 by Biegel was not reverted
https://www.wikidata.org/w/index.php?diff=508999044 by Yhteistyössä was not reverted
https://www.wikidata.org/w/index.php?diff=509004226 by Yhteistyössä was not reverted
https://www.wikidata.org/w/index.php?diff=509023989 by Biegel was not reverted
https://www.wikidata.org/w/index.php?diff=509042748 by 2405:3800:80:6526:D030:36BF:522D:34C0 was not reverted
https://www.wikidata.org/w/index.php?diff=509049975 by Mr. Andro was not reverted
https://www.wikidata.org/w/index.php?diff=509050844 by Mr. Andro was not reverted
https://www.wikidata.org/w/index.php?diff=509052032 by Omarooo55 was not reverted
https://www.wikidata.org/w/index.php?diff=509073143 by 5.120.93.10 was not reverted
https://www.wikidata.org/w/index.php?diff=509102113 by 2.50.155.22 was not reverted
https://www.wikidata.org/w/index.php?diff=509106412 by مهيمن الونسو was not reverted
https://www.wikidata.org/w/index.php?diff=509107298 by MathKnight-at-TAU was not reverted
https://www.wikidata.org/w/index.php?diff=509115897 by 87.117.37.100 was not reverted
https://www.wikidata.org/w/index.php?diff=509116285 by 87.117.37.100 was not reverted
https://www.wikidata.org/w/index.php?diff=509118663 by Jaochaytheminta apimahasetteenattapon was not reverted
https://www.wikidata.org/w/index.php?diff=509121098 by Jaochaytheminta apimahasetteenattapon was not reverted
https://www.wikidata.org/w/index.php?diff=509122474 by MathKnight-at-TAU was not reverted
https://www.wikidata.org/w/index.php?diff=509126952 by MathKnight-at-TAU was not reverted
https://www.wikidata.org/w/index.php?diff=509137276 by MathKnight-at-TAU was not reverted
https://www.wikidata.org/w/index.php?diff=509148116 by 197.47.76.56 was not reverted
https://www.wikidata.org/w/index.php?diff=509153856 by 217.24.148.90 was reverted by 217.24.148.90
https://www.wikidata.org/w/index.php?diff=509154165 by 217.24.148.90 was not reverted
https://www.wikidata.org/w/index.php?diff=509164114 by 178.137.17.113 was not reverted
https://www.wikidata.org/w/index.php?diff=509165462 by 178.137.17.113 was not reverted
https://www.wikidata.org/w/index.php?diff=509179208 by 160.105.64.211 was not reverted
https://www.wikidata.org/w/index.php?diff=509186469 by 105.139.41.249 was not reverted
https://www.wikidata.org/w/index.php?diff=509199509 by 185.54.205.44 was not reverted
https://www.wikidata.org/w/index.php?diff=509210828 by VV94 was not reverted
https://www.wikidata.org/w/index.php?diff=509213304 by Davida975 was not reverted
https://www.wikidata.org/w/index.php?diff=509230881 by Mrs markiza was not reverted
https://www.wikidata.org/w/index.php?diff=509231671 by Mrs markiza was not reverted
# another revert detection test

#rev_id = 458335404
rev_id = 474229667 # this one was actually reverted, in https://www.wikidata.org/w/index.php?title=Q2411437&diff=next&oldid=474229667
try:
            _, reverted, reverted_to = mwreverts.api.check(
                session, rev_id, radius=5,  # most reverts happen within 5 edits
                window=48*60*60,  # 2 days
                rvprop={'user', 'ids'})  # Some properties we may make use of later
except RuntimeError as e:
            sys.stderr.write(str(e))
        

if reverted:
            print('https://www.wikidata.org/w/index.php?diff=' + str(rev_id) + ' was reverted by '+ reverted.reverting['user'])
else:
            print('https://www.wikidata.org/w/index.php?diff=' + str(rev_id) + ' was not reverted')
https://www.wikidata.org/w/index.php?diff=474229667 was not reverted
rev = appedits[4001]
rev
(465309997,
 b'20170312081512',
 b'/* wbsetdescription-add:1|ru */ \xd0\xbe\xd0\xbe',
 b'188.230.45.182',
 0)
re.match(r'[^\|]*\|([^ ]*)',rev[2].decode()).group(1)
'pl'
for i in range(45000,45099):
    print(re.match(r'[^\|]*\|([^ ]*)',appedits[i][2].decode()).group(1))
he
it
pt
it
it
ru
ru
es
ro
pt
ga
ga
ga
ga
ga
ga
fr
he
he
fi
fi
fa
pt
fa
it
hi
es
pl
pl
sh
es
ja
es
es
ar
tr
de
de
de
es
de
it
bn
af
fr
ru
es
es
fr
it
de
ga
ga
ga
ga
ja
ja
ga
ja
ga
ja
ga
ga
ja
ja
ga
ja
ga
ja
ga
ga
ja
ga
ga
ja
ja
ja
ga
ga
ga
ga
ga
ar
pt
hi
ru
bn
de
uk
uk
fr
mai
ar
mai
fi
mai
it
ne
ne