Es ist ein Inhalt, den ich mit dem Sammeln von Informationen aus arxiv und dem Versuch, nützliche Informationen zu erhalten, spiele. Das Verfahren, das ich dieses Mal gemacht habe, ist wie folgt.
Ich frage mich, ob ich einen Cluster wie eine große Forschungsgruppe im Forschungsbereich sehen kann, der sich auf geeignete Schlüsselwörter bezieht. Schließlich wird das in der folgenden Grafik gezeigte Co-Autorennetzwerk (abhängig von der Anzahl der Beiträge) extrahiert.
Dies ist ein Co-Autorennetzwerk, wenn arxivs Quant-Ph-Artikel von 2015 bis 2020 ausgewählt werden, die "Quantencomputer" im Titel / Absolut enthalten, und nur die Autoren mit 15 oder mehr anwendbaren Artikeln ausgewählt werden. (Die Dichte der Seiten ist die Anzahl der mitverfassten Artikel, die für jeden Cluster standardisiert wurden.)
** (Ergänzung: Die Notationsschwankung des Autorennamens wurde aktualisiert und die Daten wurden korrigiert.) **
Normales Scraping in Python. (Es gab auch eine arxiv API) Klicken Sie direkt auf die erweiterte Suche von arxiv, um sie aufzunehmen. Die jährlich gesammelten Informationen werden in einen Pandas DataFrame konvertiert und als CSV-Datei gespeichert.
Die zu sammelnden Informationen
Immerhin gibt es einige Informationen, die ich diesmal nicht verwendet habe.
** * Der Code wurde korrigiert, da er aufgrund der Spezifikationen von arxiv nicht funktioniert, wenn die Anzahl der Suchziele für ein Jahr 10.000 überschreitet. Wenn Sie die Anzahl der Fälle überprüfen und diese überschreiten, suchen Sie monatlich und sammeln Sie Daten. ** ** **
from bs4 import BeautifulSoup
import requests
import re
import pandas as pd
import numpy as np
import math
def month_string_to_number(string):
m = {
'jan': 1,
'feb': 2,
'mar': 3,
'apr':4,
'may':5,
'jun':6,
'jul':7,
'aug':8,
'sep':9,
'oct':10,
'nov':11,
'dec':12
}
s = string.strip()[:3].lower()
try:
out = m[s]
return out
except:
raise ValueError('Not a month')
#Die Anzahl der Suchergebnisse erhalten Sie auf der Suchergebnisseite
def get_number_of_searchresult(url):
html_doc = requests.get(url).text
soup = BeautifulSoup(html_doc, "html.parser")
tags = soup.find_all("h1",{"class":"title is-clearfix"})
text = tags[0].text.strip()
if "Showing" in text and "results" in text:
stext = text.split(" ")
datanum = int(stext[3].replace(',', ''))#Holen Sie sich die Anzahl der Suchergebnisse
else:
datanum=math.nan
return datanum
#Holen Sie sich Informationen aus den Suchergebnissen und np.ndarray
def collect_info_from_advancedsearch(urlhead, datanum,key):
titles=[]#Liste zur Datenspeicherung
absts=[]#Abst
cites=[]#Informationen zitieren(arxiv:XXXXXX)
authors=[]# author
dates=[]#Datumsangaben
dates_orig_m =[]#Erster Buchungsmonat
dates_orig_y =[]#Erstes Buchungsjahr
dois = []#doi
fields=[]#cross-Feldinformationen einschließlich Liste
startnum=0
while datanum > startnum:
print(str(startnum)+"...", end="")
url = urlhead+str(startnum)#URL der erweiterten Suche
html_doc = requests.get(url).text
soup = BeautifulSoup(html_doc, "html.parser")
#Titelinformationen
tags1= soup.find_all("p", {"class": "title is-5 mathjax"})
titles_tmp = [tag.text.strip() for tag in tags1]
#Informationen enthalten
tags2 = soup.find_all("span", {"class": "abstract-full has-text-grey-dark mathjax"})
absts_tmp = [tag.text[:-7].strip() for tag in tags2 if "Less" in tag.text]
#Informationen zitieren
tags3 =soup.find_all("p", {"class": "list-title is-inline-block"})
cites_tmp = [tag.select("a")[0].text for tag in tags3]
#Datumsangaben
tags4 = soup.find_all("p",{"class":"is-size-7"})
text = [tag.text.strip() for tag in tags4 if "originally announced" in tag.text ]
dates_tmp = text
dates_orig_y_tmp=[txt.split(" ")[-1][:-1] for txt in text]
dates_orig_m_tmp=[month_string_to_number(txt.split(" ")[-2]) for txt in text]
#DOI-Informationen
tags5 = soup.find_all("div",{"class":"is-marginless"})
dois_tmp = [tag.text[tag.text.rfind("doi"):].split("\n")[1] for tag in tags5 if key in tag.text ]
#Informationen zum Autor
tags6= soup.find_all("p", {"class": "authors"})
auths_tmp = []
for tag in tags6:
auths=tag.select("a")
authlist=[(author.text,author.get("href")[33:]) for author in auths]
auths_tmp.append(authlist)
# Cross-Informationen auflisten
tags7= soup.find_all("div", {"class": "tags is-inline-block"}) # title#("span", {"class": "tag is-small is-link tooltip is-tooltip-top"}) # title
fields_tmp=[tag.text.strip().split("\n") for tag in tags7]
#Zu den Ergebnissen hinzufügen
titles.extend(titles_tmp)
absts.extend(absts_tmp)
cites.extend(cites_tmp)
authors.extend(auths_tmp)
dates.extend(dates_tmp)
dates_orig_y.extend(dates_orig_y_tmp)
dates_orig_m.extend(dates_orig_m_tmp)
dois.extend(dois_tmp)
fields.extend(fields_tmp)
#Aktualisieren Sie die Startnummer auf der nächsten Seite der Suchergebnisse
startnum += sizenum
nt = np.array(titles)
na = np.array(absts)
nauth = np.array(authors)
ncite = np.array(cites)
nd = np.array(dates)
ndy = np.array(dates_orig_y)
ndm = np.array(dates_orig_m)
ndoi = np.array(dois)
nfields=np.array(fields)
npdataset = np.concatenate([[ncite],[nt],[na],[nauth],[nfields],[ndoi],[ndy],[ndm],[nd]],axis=0).T
print(" collected data number : ", npdataset.shape[0])
return npdataset
#Wörterbuch zum Festlegen der Suchzielklassifizierung der Suchabfrage
dict_class={'cs': '&classification-computer_science=y',
'econ': '&classification-economics=y',
'eess': '&classification-eess=y',
'math': '&classification-mathematics=y',
'q-bio': '&classification-q_biology=y',
'q-fin': '&classification-q_finance=y',
'stat': '&classification-statistics=y',
'all': '&classification-physics=y&classification-physics_archives=all',
'astro-ph': '&classification-physics=y&classification-physics_archives=astro-ph',
'cond-mat': '&classification-physics=y&classification-physics_archives=cond-mat',
'gr-qc': '&classification-physics=y&classification-physics_archives=gr-qc',
'hep-ex': '&classification-physics=y&classification-physics_archives=hep-ex',
'hep-lat': '&classification-physics=y&classification-physics_archives=hep-lat',
'hep-ph': '&classification-physics=y&classification-physics_archives=hep-ph',
'hep-th': '&classification-physics=y&classification-physics_archives=hep-th',
'math-ph': '&classification-physics=y&classification-physics_archives=math-ph',
'nlin': '&classification-physics=y&classification-physics_archives=nlin',
'nucl-ex': '&classification-physics=y&classification-physics_archives=nucl-ex',
'nucl-th': '&classification-physics=y&classification-physics_archives=nucl-th',
'physics': '&classification-physics=y&classification-physics_archives=physics',
'quant-ph': '&classification-physics=y&classification-physics_archives=quant-ph'}
years = [y for y in range(2015,2020)]
key = "quant-ph"#Suchzielfeld diktieren_Geben Sie den Schlüssel der Klasse an
output_fname="df_quant-ph" #Name der Ausgabedatei
url0="https://arxiv.org/search/advanced?advanced=&terms-0-operator=AND&terms-0-term=&terms-0-field=title"
url1="&classification-include_cross_list=include"
url_daterange="&date-year=&date-filter_by=date_range"
url2="&date-date_type=submitted_date&abstracts=show&size="
urlmid = "&order=-announced_date_first&start="
sizenum = 25
startnum=0
for year in years:
m_divide = 1 #Anzahl der Abteilungen im Suchzeitraum
mstart =1
mstop = 1
url_date = "&date-from_date="+str(year)+"-"+str(mstart).zfill(2)+"-01&date-to_date="+str(year+1)+"-"+str(mstop).zfill(2)+"-01"
urlhead = url0+dict_class[key]+url1+url_daterange+url_date+url2
urlmid = "&order=-announced_date_first&start="
url = urlhead+str(sizenum)+urlmid+str(startnum)
datanum=get_number_of_searchresult(url) #Holen Sie sich die Anzahl der Suchergebnisse
print("Number of search results ("+str(year)+") : "+str(datanum))
if datanum >=10000: #Wenn die Anzahl der Fälle das Limit überschreitet, wird die Datenerfassung für ein Jahr durch den Monat geteilt.
m_divide = 13
for month_divide in range(2,12): #Suchen Sie nach der Anzahl der Abteilungen, bei denen die Anzahl der Einzelfälle kleiner oder gleich dem Grenzwert ist
flag_numlimit = False
for idx in range(month_divide):
mstart = int(idx*12/month_divide+1)
mstop = (int((idx+1)*12/month_divide)+1)%12
if mstop !=1:
url_date = "&date-from_date="+str(year)+"-"+str(mstart).zfill(2)+"-01&date-to_date="+str(year)+"-"+str(mstop).zfill(2)+"-01"
else:
url_date = "&date-from_date="+str(year)+"-"+str(mstart).zfill(2)+"-01&date-to_date="+str(year+1)+"-"+str(mstop).zfill(2)+"-01"
urlhead = url0+dict_class[key]+url1+url_daterange+url_date+url2
url = urlhead+str(sizenum)+urlmid+str(startnum)
datanum=get_number_of_searchresult(url)#Ermitteln Sie die Anzahl der Daten für jede Anzahl von Abteilungen
if datanum >= 10000:
flag_numlimit = True
if not flag_numlimit:
m_divide = month_divide
break
if m_divide > 12:
print("*** Number of search result is over the limit 10,000. Please refine your search. ***")
sizenum=200
npdataset = np.empty((0,9))
for idx in range(m_divide):
mstart = int(idx*12/m_divide+1)
mstop = (int((idx+1)*12/m_divide)+1)%12
if mstop !=1:
url_date = "&date-from_date="+str(year)+"-"+str(mstart).zfill(2)+"-01&date-to_date="+str(year)+"-"+str(mstop).zfill(2)+"-01"
else:
url_date = "&date-from_date="+str(year)+"-"+str(mstart).zfill(2)+"-01&date-to_date="+str(year+1)+"-"+str(mstop).zfill(2)+"-01"
urlhead = url0+dict_class[key]+url1+url_daterange+url_date+url2
url = urlhead+str(25)+urlmid+str(0)
datanum=get_number_of_searchresult(url)
print("Collect search results ..." + url_date + ", Number of search results : " + str(datanum))
urlhead2 = urlhead+str(sizenum)+urlmid
npdataset_tmp = collect_info_from_advancedsearch(urlhead2,datanum,key)
npdataset = np.concatenate([npdataset, npdataset_tmp], axis=0)
#Konvertieren Sie Informationen im Wert von einem Jahr in numpy und pandas DataFrame und speichern Sie sie in csv
dataset = pd.DataFrame(npdataset)
dataset.columns =["Cite","Title","Abst","Authors","Fields","DOI", "OrigDateY","OrigDateM","Date Info"]
dataset.to_csv(output_fname+str(year)+".csv")
Lesen und verketten Sie die für jedes Jahr gesammelte CSV. Extrahieren Sie Titel und Abstracts, die Schlüsselwörter für verkettete Datasets enthalten. Dieses Mal lautet das Schlüsselwort Quantenberechnung.
fname_head = "df_quant-ph"
fname = fname_head + str(2020)+".csv"
dataset = pd.read_csv(fname, index_col=0)
for year in range(2010,2020):
fname = fname_head + str(year)+".csv"
print(fname)
dataset_tmp = pd.read_csv(fname, index_col=0)
dataset = pd.concat([dataset,dataset_tmp])
dataset =dataset.reset_index()
dataset_r=dataset.query('title.str.contains("quantum comput") or abst.str.contains("quantum comput")', engine='python')
Ich dachte jedoch, dass dieses Formular nicht richtig nach Fallproblemen und anderen Suchwörtern suchen kann. Wir haben auch die Stemming-Verarbeitung mit nltk hinzugefügt. Es basiert auf hier. Ich habe vorerst Lemmatization geschrieben, aber ich kommentiere es jetzt aus.
import re
import nltk
from nltk.corpus import stopwords
from nltk.stem.porter import PorterStemmer
from nltk.stem.wordnet import WordNetLemmatizer
from nltk.corpus import stopwords
def preprocess_text(text):
text = re.sub('[^a-zA-Z]', ' ', text)#Remove punctuations
text = text.lower()
text=re.sub("</?.*?>"," <> ",text)#remove tags
text=re.sub("(\\d|\\W)+"," ",text)# remove special characters and digits
text = text.split()
stop_words = set(stopwords.words("english"))
##Stemming
#Lemmatisation
ps=PorterStemmer()
#lem = WordNetLemmatizer()
text = [ps.stem(word) for word in text if not word in stop_words]
text=" ".join(text)
return text
ndata = (dataset['Title']+" "+ dataset['Abst']).values
ndata= np.array([preprocess_text(text) for text in ndata])
dataset['Keywords'] = ndata
dataset_r=dataset.query('Keywords.str.contains("quantum comput")', engine='python')
Verwenden Sie networkx, um ein gerichtetes Diagramm (oben sind Autorenname und Artikelnummer) mit der Beziehung zwischen Artikel und Autor als Kanten zu zeichnen. Ich mache etwas Seltsames, weil ich die Autoreninformationen in ein Format lege, das schwer zu lesen ist.
Nachtrag: In Bezug auf Schwankungen wie einen Teil des Namens, der initialisiert wird oder nicht, außer Familienname? Nimmt Daten mithilfe der initialisierten Abfragezeichenfolge auf. (Für die Notation wird einer der häufigsten Werte ausgewählt. Wenn Sie ihn ändern möchten, ändern Sie das Wörterbuch auth_dict separat.) Es kann jedoch Autorennamen geben, die überkombiniert sind, da sie von der initialisierten Zeichenfolge durchsucht werden. Wenn Sie klassifizieren möchten, wie es ist, verwenden Sie den auskommentierten Autnamen.
authtext = " ".join(auths)
match = re.findall(r"(\()(.*?)\)",authtext)
for key in auth_dict.keys():
l=[m[1].split(m[1][0])[1] for m in match if key in m[1]]
c = collections.Counter(l)
print(c.most_common())
import networkx as nx
import collections
auths= dataset_r['Authors'].values
datanum = auths.shape[0]
#Erstellen eines Autorennamenwörterbuchs
auth_dict = {}
for idx in range(datanum):
match = re.findall(r"(\()(.*?)\)",auths[idx])
for m in match:
auth = m[1].split(m[1][-1])[-2]
authname = m[1].split(m[1][0])[1]
auth_dict[auth]=authname
#Ändern Sie jedes Element im Wörterbuch auf den häufigsten Wert
authtext = " ".join(auths)
match = re.findall(r"(\()(.*?)\)",authtext)
for key in auth_dict.keys():
l=[m[1].split(m[1][0])[1] for m in match if key in m[1]]
c = collections.Counter(l)
auth_dict[key]=c.most_common()[0][0]
#Fügen Sie dem Diagramm Informationen hinzu
G=nx.DiGraph()
for idx in range(datanum):
match = re.findall(r"(\()(.*?)\)",auths[idx])
for m in match:
auth = m[1].split(m[1][-1])[-2]
#authname = m[1].split(m[1][0])[1]#Wenn Sie ein Diagramm mit der aktuellen Notation erstellen möchten, fügen Sie eine Seite mit diesem Autnamen hinzu
G.add_edges_from([(idx,auth_dict[auth])])
Schließen Sie für jeden Autor Autoren mit einer kleinen Anzahl von Artikeln aus der Grafik aus. (Diesmal 15 oder weniger gelöscht) Infolgedessen werden diejenigen ausgeschlossen, deren Reihenfolge für jedes Papier 0 ist.
thr=15
authorlist = [n for n in G.nodes() if type(n) is str]
for auth in authorlist:
deg=G.degree(auth)
if deg <=thr:
G.remove_node(auth)
for idx in range(datanum):
deg=G.degree(idx)
if deg <=0:
G.remove_node(idx)
Zeichnen Sie das resultierende Diagramm. Zeichnen Sie den Autor in Blau und das Papier in Rot Ich versuche, wichtige Eckpunkte mit PageRank zu vergrößern. Dieser Artikel wird als Referenz verwendet.
def draw_graph(G, label = False):
#Berechnung des Pageranks
pr = nx.pagerank(G)
pos = nx.spring_layout(G)
fig = plt.figure(figsize=(8.0, 6.0))
c=[(0.4,0.4,1) if type(n) is str else (1,0.4,0.4) for n in G.nodes()]
nx.draw_networkx_edges(G,pos, edge_color=(0.3,0.3,0.3))
nx.draw_networkx_nodes(G,pos, node_color=c, node_size=[5000*v for v in pr.values()])
Das Ausgabeergebnis ist wie folgt. Viele Artikel befinden sich in einem Zustand, in dem sie sich nur auf einen Autor beziehen.
Vorläufig interessierte ich mich für das Co-Autorennetzwerk, daher werden die Informationen in dem Artikel gewichtet.
import itertools
def convert_weightedGraph(graph):
graph_new =nx.Graph()
for node in graph.nodes:
if type(node) is str:
continue
n_new = [e[1] for e in graph.edges if e[0]==node]
for e_new in itertools.permutations(n_new, 2):
flag_dup = False
for e_check in graph_new.edges(data=True):
if e_new[0] in e_check and e_new[1] in e_check:
e_check[2]['weight']+=1
flag_dup = True
if not flag_dup:
graph_new.add_edge(e_new[0],e_new[1],weight=1)
return graph_new
wG=convert_weightedGraph(G)
Zeichnen Sie das erhaltene Diagramm mit der folgenden Funktion. Wenn sich die Beschriftungen überschneiden, können Sie sie an die Größe der Abbildung oder das Argument k von spring_layout anpassen. (Referenz)
def draw_weightedG(G):
fig = plt.figure(figsize=(8.0, 6.0))
pr = nx.pagerank(G)
pos = nx.fruchterman_reingold_layout(G,k=k0/math.sqrt(G.order()))
#pos = nx.spring_layout(G,k=15/math.sqrt(G.order()))
#Verwenden Sie ein geeignetes Layout. Passen Sie den Abstand zwischen Knoten mit dem Wert von k an
x_values, y_values = zip(*pos.values())
x_max = max(x_values)
x_min = min(x_values)
x_margin = (x_max - x_min) * 0.25
plt.xlim(x_min - x_margin, x_max + x_margin) #Sichern Sie einen Rand, damit die Beschriftungszeichen nicht abgeschnitten werden
node_sizes=[5000*v for v in pr.values()]
edge_colors = [e[2]['weight'] for e in G.edges(data=True)] #Färbung mit Seitengewichten
nodes = nx.draw_networkx_nodes(G, pos, node_size=node_sizes, node_color='#9999ff')
edges = nx.draw_networkx_edges(G, pos, node_size=node_sizes, arrowstyle='->',
arrowsize=10, edge_color=edge_colors,
edge_cmap=plt.cm.Blues, width=2)
nx.draw_networkx_labels(G,pos)
ax = plt.gca()
ax.set_axis_off()
Anhand des Zeichnungsergebnisses des erhaltenen Diagramms können Sie erkennen, dass ein nicht verbundenes Teildiagramm vorhanden ist.
Wir werden von jedem Knoten des Graphen aus einen zusammenhängenden Teilgraphen erstellen. Ich hatte kein Werkzeug, das ich auf einen Blick verwenden konnte, also schrieb ich es solide.
def add_edges_to_wsubgraph(subg, edge_new,node,edges_all):
subg.add_edges_from([edge_new])
if node == edge_new[1]:
node_new = edge_new[0]
else:
node_new = edge_new[1]
edges_new = [e for e in edges_all if node_new in e and e not in subg.edges(data=True)]
for edge in edges_new:
if edge not in subg.edges(data=True):
add_edges_to_wsubgraph(subg,edge,node_new,edges_all)
def separate_wG_by_connectivity(G):
nodes_all =[n for n in G.nodes()]
edges_all = [e for e in G.edges(data=True)]
subgraphs = []
for node in nodes_all:
usedflag = any([node in g.nodes for g in subgraphs])
if usedflag:
continue
subg = nx.Graph()
subg.add_node(node)
edges_new = [e for e in edges_all if node in e]
for edge in edges_new:
if edge not in subg.edges(data=True):
add_edges_to_wsubgraph(subg,edge,node,edges_all)
subgraphs.append(subg)
return subgraphs
subgraphs = separate_wG_by_connectivity(wG)
Wenn Sie jedes der hier erhaltenen Teilgraphen zeichnen Sie erhalten die folgenden drei Grafiken. (Manuell zu einem Bild gemacht)
cnt=0
for subg in subgraphs:#Zeichnen Sie ein Teildiagramm und speichern Sie das Bild
draw_weightedG(subg)
plt.savefig("subgraph_"+str(cnt)+".png ")
plt.cla()
cnt+=1
Beginnend mit der Datenerfassung von arxiv habe ich eine netzwerkähnliche Sache mit einem Autor über ein bestimmtes Schlüsselwort geschrieben. Ich habe relativ saubere Ergebnisse erzielt, aber in einigen Fällen blieben nur große Cluster übrig, abhängig von den Suchwörtern und den Schwellenwerteinstellungen. In einem solchen Fall kann es möglich sein, ein wenig detaillierter zu werden, indem die Anzahl der mitverfassten Artikel, die das Gewicht der Seiten sind, auf einen geeigneten Schwellenwert gesenkt wird. Danach denke ich, dass es interessant wäre, die Zitierbeziehung des Papiers zu erfahren, aber ich konnte mir keine einfache Informationsquelle vorstellen, also würde ich mich freuen, wenn Sie mir etwas sagen könnten.
Recommended Posts