====== Novi podatki z NBER ====== 28. July 2011 ===== Predelava za Pajka in R ===== Nove podatke o ameriških patentih 1976-2006 je mogoče najti na http://elsa.berkeley.edu/~bhhall/NBER06.html . Za predelavo v Pajkove in R-jeve datoteteke sem (27. september 2010) moral uporabiti 64-bitni računalnik. Šlo je brez težav, le kar nekaj časa potrebuje. > memory.size() [1] 10.58383 > memory.limit() [1] 3583.875 > getwd() [1] "C:/Users/batagelj.FMF1/work/R/nber" > library(foreign) > a <- read.dta("cite76_06.dta") > save(a,file="nberCite.Rdata") > names(a) [1] "citing" "cited" "ncites7606" > b <- as.matrix(a) > dim(b) [1] 23650891 3 > b[1:10,] citing cited ncites7606 1 5135226 3930271 6 2 5592695 3930271 6 3 5621918 3930271 6 4 5624296 3930271 6 5 5675839 3930271 6 6 6725465 3930271 6 7 4084277 3930273 20 8 4206525 3930273 20 9 4509217 3930273 20 10 4985946 3930273 20 > nrow(b) [1] 23650891 > max(b[,1]) [1] 7155745 > max(b[,2]) [1] 7118895 > n <- max(b[,1]) > net <- file("nber.net","w") > cat('% NBER Patent data for 1976-2006\n% transformed in Pajek format,',date(),'\n',file=net) > cat('*vertices',n,'\n*arcs\n',file=net) > for(i in 1:nrow(b)) cat(b[i,1],b[i,2],'\n',file=net) > close(net) > > remove(a) > remove(b) > d <- read.dta("patsic06_mar09_ipc.dta") > names(d) [1] "appyear" "assignee" "cat" "gyear" "icl" "icl_class" [7] "icl_maingroup" "iclnum" "nclass" "patent" "pdpass" "subcat" [13] "subclass" > length(d$cat) [1] 4855982 > save(d,file="nberData.Rdata") Podatke sem shranil v R-jevski obliki Rdata * http://educa.fmf.uni-lj.si/datana/pub/nber/nberData.Rdata (69.4 Mb) * http://educa.fmf.uni-lj.si/datana/pub/nber/nberCite.Rdata (136.4 Mb) Naložimo jih preprosto z ukazom ''load(''file'')''. Ker tretji stolpec v podatkih nberCite ni potreben, sem podatke že predelal v Pajkovo omrežje in pozipal. Drugi zip vsebuje pozipano datoteko nberData. * http://educa.fmf.uni-lj.si/datana/pub/nber/nberData.zip (57.0 Mb) * http://educa.fmf.uni-lj.si/datana/pub/nber/nberCite.zip (116.9 Mb) Za lažje delo s podatki sem vsak stolpec izpisal na svojo datoteko: > setwd("C:/Users/batagelj.FMF1/work/R/nber") > load(file="nberData.Rdata") > objects() [1] "d" > names(d) [1] "appyear" "assignee" "cat" "gyear" "icl" "icl_class" "icl_maingroup" [8] "iclnum" "nclass" "patent" "pdpass" "subcat" "subclass" > for(n in names(d)) {txt <- file(paste(n,".txt",sep=''),"w"); cat(d[[n]],sep='\n',file=txt); close(txt)} in spravil v zip: * http://educa.fmf.uni-lj.si/datana/pub/nber/nberCols.zip (59.2 Mb) Potem sem predelal še omrežje sklicevanj v Pajkovo omrežje > setwd("C:/Users/batagelj.FMF1/work/R/nber") > library(foreign) > pati <- function(p) { + q <- as.character(p) + if(exists(q,env=patents,inherits=FALSE)) return(get(q,env=patents,inherits=FALSE)) else { + np <<- np+1; cat(np,' "',p,'"\n',sep='',file=vtx); assign(q,np,env=patents); return(np) + } + } > pat <- readLines(con<-file("./Cols/patent.txt","r")); close(con) > vtx <- file("nber.vtx","w") > patents <- new.env(hash=TRUE,parent=emptyenv(),size=4000000) > np <- 0 > for(p in pat) if(!exists(p,env=patents,inherits=FALSE)){ + np <- np+1; cat(np,' "',p,'"\n',sep='',file=vtx); assign(p,np,env=patents)} > a <- as.matrix(read.dta("cite76_06.dta")) > edg <- file("nber.edg","w") > for(i in 1:nrow(a)) cat(pati(a[i,1]),pati(a[i,2]),'\n',file=edg) > close(edg) > close(vtx) Na datoteki ''nber.vtx'' sem najprej zbral vse patente iz stolpca ''patent'' iz podatkov. Spočetka sem nameraval to narediti tako, da bi točke imele kar zaporedno številko, ki ustreza podatku ''patent'' v stolpcih. Nastopile so težave > pat <- readLines(con<-file("./Cols/patent.txt","r")); close(con) > length(pat) [1] 4855982 > pat[1:5] [1] "3930271" "3930272" "3930273" "3930273" "3930274" > ass <- readLines(con<-file("./Cols/assignee.txt","r")); close(con) > ass[1:5] [1] "251415" "246000" "10490" "10490" "0" Zgleda, da se lahko ista patentna številka nahaja v več vrsticah - npr. ''"3930273"''. Nekaj o tem piše tudi na http://elsa.berkeley.edu/~bhhall/NBER06.html . Nekje bi bilo dobro izvedeti, kaj je mišljeno z "observation". Zato sem se odločil, da upoštevam samo različne. Teh je 3209376. Izkaže pa se, da so v omrežju sklicevanj patenti, ki nimajo nobenega opisa v podatkih. Te sem dodal na konec datoteke, ki ima tako skupaj 3210774 točk. Povezave omrežja sem izpisal na datoteko ''nber.edg'' . Obe datoteki sem nato ročno dopolnil do ustreznih Pajkovih datotek ''nber60.nam'' (izpopolnjena ''nber.vtx'' - vsebuje imena točk; dodamo jih po potrebi izpeljanim omrežjem z ukazom ''Net/Transform/Add/Vertex Labels from File'') in ''nber60Cite.net'' (izpopolnjena ''nber.edg'' - omrežje sklicevanj brez imen v Pajkovi obliki). Ker R naravna števila, ki se končajo z vsaj 5 ničlami izpiše v eksponentni obliki (ostale izpiše v pričakovani obliki), je bilo pri predelavi obeh datotek potrebno zamenjati vse ''e+05'' z ''00000'' in vse ''e+06'' z ''000000''. Lahko bi sicer popravljal ukaze in izpisoval s funkcijo ''format'', a ker obdelava teče več kot 2 uri, sem se odločil kar za ročni popravek. Datoteki sta shranjeni v zip * http://educa.fmf.uni-lj.si/datana/pub/nber/nber60Cite.zip (131.3 Mb) Ostane še vprašanje: **kako do podatkov o posameznem patentu?** ---- library(foreign) # construct .CLU files (from additional variables, nberCols) # construct file to help all others (which line in nberCols files to leave) pat <- readLines(con<-file("../nberCols/patent.txt","r")); close(con) f <- file("line_to_leave.txt","w") patents <- new.env(hash=TRUE,parent=emptyenv(),size=4000000) np <- 0 for(p in pat){ if(!exists(p,env=patents,inherits=FALSE)){ np <- np+1 cat('1\n',sep='',file=f) assign(p,np,env=patents) }else{ cat('0\n',sep='',file=f) } } close(f) const <- 1398 files <- list.files(path="../nberCols/") for (i in 1:length(files)){ g <- file("line_to_leave.txt","r") old <- file(paste("../nberCols/",files[i],sep=""),"r") temp <- strsplit(files[i],split=".txt") new <- file(paste("../nberCols/",temp[[1]],".clu",sep=""),"w") x <- readLines(n=1,g) while (!(length(x)==0)){ if (x=="1"){ cat(readLines(n=1,old),"\n",sep="",file=new)} else{ readLines(n=1,old)} #only read line - to get to new line x <- readLines(n=1,g) } close(old) close(g) for (i in 1:const){ # add the ones without additional data cat("0\n",sep="",file=new)} close(new) } S pomočjo zgornje kode skonstruiramo vse ".clu" datoteke. Za pravilno delovanje je potrebno stvari še malce počistiti (NA -> 9999998). Vrednosti zadnjih 1398 patentov (tistih, ki nimajo dodatnih podatkov), so vedno 0. Podobno skonstruiramo tudi datoteko "described.clu". Opisi datotek: CLUSTERS (3210774 patents, 3209376 have additional information) --- described.clu (1 for those with additional information - first 3209376, others 0) appyear.clu (application year) assignee.clu (assignee id) gyear.clu (grant year) cat.clu (HJT category - 1-6) subcat.clu (HJT subcategory - 2-digit) --- not cleaned! - will not be used for the book icl_class.clu (Main 4-char IPC) icl_maingroup.clu (Main group within 4char IPC) iclnum.clu (clas/icl seq. number (imc)) nclass.clu (3-digit US patent class (10=D)) subclass.clu (numerical subclass) --- not everything included (see constructed 2-mode networks), not cleaned! icl.clu (clas/ international classification) pdpass.clu (unique assignee number for match in CompuStat) Zadnji 2 datoteki pretvorimo v 2-vrstna omrežja (podobno - s hranjenjem vrednosti v 2 "environment"-a). 2-MODE (3210774 patents + second mode) ---- icl_simple.net (second mode: 170548) icl.nam pdpass_simple.net (second mode: 223943) pdpass.nam Datoteke: * {{::book:temp:private:data:clusters.zip|clusters.zip}} (37.2 MB) * {{::book:temp:private:data:icl_2mode.zip|icl_2mode.zip}} (37.7 MB) * {{::book:temp:private:data:pdpass_2mode.zip|pdpass_2mode.zip}} (31.3 MB) ===== Naslovi in avtorji patentov ===== Naslednji program v R-ju zbira dodatne podatke o patentih: naslov patenta in avtorje (kraj, država). Številke patentov pobira iz pajkovega seznama 'imen' patentov z datoteke ''nber06.nam''. # Collecting title + inventors info from US patent Office # http://patft.uspto.gov/netahtml/PTO/srchnum.htm # Vladimir Batagelj, July 22, 2011 readURL <- function(page,repo,save){ e<-NULL for(a in 1:10){ stran <- tryCatch(readLines(con<-url(page),warn=FALSE,n=100), error = function(e) e,finally=close(con)) ok <- class(stran)=="character" if(ok) return(stran) if (a<6) cat('\n*** class = ',class(stran),'\nretry',a,':',date(),'\n',file=repo) if (a<10) { cat('\n*** class = ',class(stran),'\nretry',a,':',date(),'\n') flush.console()} Sys.sleep(60) } cat("Problems on the Internet ...\nClosing",date(),'\n',file=repo) cat("Problems on the Internet ...\nClosing",date(),'\n') close(repo); close(save); stop("Too many retries") } setwd("D:/Data/nber/titles") repo <- file("report-400Mc.txt","w") save <- file("titles-400Mc.dat","w") nums <- read.csv("nber06.nam",sep=' ',header=FALSE,skip=1,stringsAsFactors=FALSE)$V2 url1 <- 'http://patft.uspto.gov/netacgi/nph-Parser?Sect2=PTO1&Sect2=HITOFF&p=1'+ '&u=%2Fnetahtml%2FPTO%2Fsearch-bool.html&r=1&f=G&l=50&d=PALL&RefSrch=yes&Query=PN%2F' k <- 281387; K <- 400000 cat('% NBER - patent titles\n% started at,',k,'-',K,':',date(),'\n\n',file=repo) while(k < K){ if(k %% 100==0) { if(k %% 5000==0) {cat('\n',k,' ',date(),' ',sep=''); flush.console() cat(k,' ',date(),'\n',sep='',file=repo) } cat('.'); flush.console() } k <- k+1; patNum <- nums[k] stran <- readURL(paste(url1,patNum,sep=''),repo,save) it <- grep('',stran,fixed=TRUE) if (length(it)>0){ ti <- it[1]; str <- stran[ti]; lt <- nchar(str) jt <- regexpr('> ',str); tit <- substr(str,jt+2,lt) cat(k,'=',patNum,'="',tit,'"\n',sep='',file=save) } else { cat(k,patNum,' - missing title\n',file=repo) } ii <- grep('>Inventors:',stran,fixed=TRUE) if (length(ii)>0){ ti <- ii[1]; str <- stran[ti+1]; lt <- nchar(str) jt <- regexpr('',str); inv <- substr(str,1,jt-1) cat(inv,'\n',sep='',file=save) } else { cat(k,patNum,' - missing inventors\n',file=repo) } } close(repo); close(save) Pozor, pri branju preberemo le prvih 100 vrstic: ''readLines(con<-url(page),warn=FALSE,n=100)'' Zbiranje poteka precej počasi - okrog 2500 patentov na uro. Zato stvar pohitrimo z izvajanjem večih izvodov programa na različnih delih (k,K) seznama patentov. Iz zbranih podatkov ustvarimo Pajkovo datoteko z dolgimi imeni (naslovi patentov) v načrtu pa so še dvovrstna omrežja patents X keywords (pridobljeni iz naslovov), patents X authors in patents X states. import re import sys; wdir = r'd:\data\nber\titles'; sys.path.append(wdir) titFile=wdir+'\\data\\titles-200Mc.dat' namFile=wdir+'\\data\\long.nam' pauFile=wdir+'\\data\\nber06.PA' dat = open(titFile,'r') nam = open(namFile,'w') pau = open(pauFile,'w') bb = "Fletcher; James C. (National Aeronautics and Space, US)" k = 0 while True: a = dat.readline() if not a: break b = dat.readline() if not b: break k = k+1 A = a.strip().split('=') nam.write(A[0]+' '+A[2]+'\n') B = b.strip()[3:] if B.startswith('Fletcher; James C. '): D = re.split(r",| |$",B) B = bb for i in range((len(D)-3) // 2): B += ','+D[2*i+4]+' '+D[2*i+3] B = B.replace('(N/A)','(**, **)').split(', ') names = [x.split('')[0] for x in B] try: C = [x.split('(',1)[1] for x in B] except: print "*** Error: C\n",A[0],A[2],'\n',b,'\n',B,'\n',C C =[x if x.rfind(',')>0 else x[:-1]+', **)' if len(x)>3 else '**, '+x for x in C] try: places = [y.rsplit(',',1)[0] for y in C] except: print "*** Error: places\n",A[0],A[2],'\n',b,'\n',B,'\n',C try: cntries = [z[3:-4] if z.startswith('') else 'US-'+z if len(z)==2 else '**-'+z for z in [ y.rsplit(', ',1)[1][:-1] for y in C]] for (i,x) in enumerate(names): pau.write(A[0]+'|'+str(i+1)+'|'+x+'|'+places[i]+'|'+ (cntries[i] if len(cntries[i])>0 else '**')+'\n') except: print "*** Error: cntries\n",A[0],A[2],'\n',b,'\n',B,'\n',C dat.close(); nam.close(); pau.close() Datoteka {{:book:temp:private:data:nber:Pyr.zip}} vsebuje datoteko ''nber06.nam'' in oba programa; datoteka {{:book:temp:private:data:nber:PyRp.zip}} pa zadnji različici obeh programov.