updated page with links to the article and full citation
[protection-tools] / 04-import_merge_data.R
1 page.restrictions.filename <- "enwiki-20150112-page_restrictions.csv"
2 page.metadata.filename <- "enwiki-20150112-page.csv"
3 log.filename <- "output-protections.tsv"
4 moves.filename <- "output-moves.tsv"
5 dels.filename <- "output-deletions.tsv"
6
7 setwd("~/protection")
8 Sys.setenv(tz = "UTC")
9 library(parallel)
10 library(data.table)
11
12 ## 0. load namespace data
13 wp.ns <- read.csv("wikipedia_namespaces.csv",
14                           header=TRUE, stringsAsFactors=FALSE)
15 # drop aliases completely
16 wp.ns <- wp.ns[!wp.ns$alias,]
17 wp.ns$alias <- NULL
18
19 setDT(wp.ns)
20 setnames(wp.ns, c("ns.num", "ns.name"))
21 wp.ns[, ns.name := gsub(' ', '_', ns.name)]
22 setkey(wp.ns, "ns.num")
23
24 ## 1. load the protection snapshot data from the parsed SQL file
25 final.state <- fread(page.restrictions.filename,
26                      header=FALSE, na.strings=NULL,
27                      colClasses=list(character=6))
28
29 setnames(final.state, c("page.id", "type", "level",
30                         "cascade", "user.id", "expiry",
31                         "id"))
32
33 # drop change several column types
34 final.state[,cascade := as.logical(cascade)]
35 final.state[,type := as.factor(type)]
36 final.state[,level := as.factor(level)]
37
38 final.state[,c("user.id", "id") := NULL]
39
40 # NULL expiry seem to be just infinite because we've confirmed that several of
41 # these pages are protected even if their expiry is null
42 final.state$expiry[final.state$expiry == "infinity"] <- NA
43 final.state$expiry[final.state$expiry == "NULL"] <- NA
44
45 final.state$expiry <- as.POSIXct(final.state$expiry,
46     format="%Y%m%d%H%M%s", tz="UTC")
47
48 # print the range
49 range(final.state$expiry, na.rm=TRUE)
50
51 setkey(final.state, "page.id")
52
53 # 2. load up the page information for the id/title mapping
54 page.info <- fread(page.metadata.filename,
55                    header=FALSE, stringsAsFactors=FALSE, na.strings=NULL,
56                    select=1:3, showProgress=TRUE)
57
58 setnames(page.info, c("page.id", "ns.num", "title"))
59
60 # merge namespace data into the data.table
61 setkey(page.info, "ns.num")
62 page.info <- wp.ns[page.info]
63 page.info[ns.num != 0, title := paste(ns.name, title, sep=":")]
64 page.info[,c("ns.num", "ns.name") := NULL]
65
66 # merge the page titles onto the final state data
67 setkey(page.info, "page.id")
68 final.state <- page.info[final.state]
69
70 # some pageids are missing (pages deleted?) so we'll drop those
71 table(is.na(final.state$title))
72 final.state <- final.state[!is.na(final.state$title),]
73
74 # 3. load the page log data from TSV file
75 log <- fread(log.filename, header=FALSE, na.strings="")
76
77 setnames(log, c("id", "title", "log.type", "log.time",
78                 "type", "level", "expiry"))
79
80 log[, log.type := as.factor(log.type)]
81 log[, type := as.factor(type)]
82 log[, level := as.factor(level)]
83 log[, log.time := as.POSIXct(log.time, tz="UTC")]
84 log[, expiry := as.POSIXct(expiry, tz="UTC")]
85 log[, title := gsub(' ', '_',  title)]
86
87 # clean up the log file by dropping some invalid data (e.g., log entries that
88 # expire before they are blocked. these are all done within the minute and seem
89 # to be a mediawiki bug (e.g., "EEE")
90 log <- log[is.na(log$expiry) | !log$expiry < log$log.time,]
91
92 # 4. load in the move data from TSV 
93 moves <- fread(moves.filename, sep="\t", header=FALSE)
94 setnames(moves, c("id", "log.time", "from.title", "to.title"))
95
96 # drop id column
97 moves[, from.title := gsub(' ', '_',  from.title)]
98 moves[, to.title := gsub(' ', '_',  to.title)]
99 moves[, log.time := as.POSIXct(log.time, tz="UTC")]
100
101 # 5. load in deletion data from the TSV file
102 dels <- fread(dels.filename, header=FALSE, na.strings="NA")
103 setnames(dels, c("id", "title", "log.type", "log.time"))
104
105 # drop id column
106 dels[, log.time := as.POSIXct(log.time, tz="UTC")]
107 dels[, title := gsub(' ', '_',  title)]
108
109 # because revision deletion does not affect protection and restoration does
110 # not restore restrictions, we can safely limit this to only delete evetns
111 # and drop this columns
112 dels <- dels[dels$log.type == "delete",]
113 dels[, log.type := NULL]
114
115 # save temporary state
116 save(log, moves, dels, final.state, file="processed_log_and_sql_data.RData")
117
118

Benjamin Mako Hill || Want to submit a patch?