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

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.

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:

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

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:

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('<font size=\"+1\">',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('</TD>',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.</B> (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> |</B>$",B)
    B = bb
    for i in range((len(D)-3) // 2):
      B += '<B>,'+D[2*i+4]+'</B> '+D[2*i+3]    
  B = B.replace('(N/A)','(**, **)').split('<B>, ')
  names = [x.split('</B>')[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('<B>') 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 pyr.zip vsebuje datoteko nber06.nam in oba programa; datoteka pyrp.zip pa zadnji različici obeh programov.

notes/clu/nber.txt · Last modified: 2017/04/10 23:59 by vlado
 
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki