Как использовать свойства DBpedia для построения иерархии тем?
Я пытаюсь построить иерархию тем, следуя приведенным ниже двум свойствам DBpedia.
- skos: более широкое свойство
- dcterms: предметная собственность
Мое намерение состоит в том, чтобы дать слово определить тему этого. Например, дано слово; "вспомогательная векторная машина", я хочу выделить из нее такие темы, как алгоритм классификации, машинное обучение и т. д.
Однако иногда я немного запутался, как построить иерархию тем, поскольку я получаю более 5 URI для субъекта и множество URI для более широких свойств. Есть ли способ измерить силу или что-то еще и уменьшить дополнительные URI, которые я получаю из DBpedia, и назначить только наиболее вероятный URI?
Кажется, здесь есть два вопроса.
- Как ограничить количество результатов DBpedia Spotlight.
- Как ограничить количество предметов и категорий для конкретного результата.
Мой текущий код выглядит следующим образом.
from SPARQLWrapper import SPARQLWrapper, JSON
import requests
import urllib.parse
## initial consts
BASE_URL = 'http://api.dbpedia-spotlight.org/en/annotate?text={text}&confidence={confidence}&support={support}'
TEXT = 'First documented in the 13th century, Berlin was the capital of the Kingdom of Prussia (1701–1918), the German Empire (1871–1918), the Weimar Republic (1919–33) and the Third Reich (1933–45). Berlin in the 1920s was the third largest municipality in the world. After World War II, the city became divided into East Berlin -- the capital of East Germany -- and West Berlin, a West German exclave surrounded by the Berlin Wall from 1961–89. Following German reunification in 1990, the city regained its status as the capital of Germany, hosting 147 foreign embassies.'
CONFIDENCE = '0.5'
SUPPORT = '120'
REQUEST = BASE_URL.format(
text=urllib.parse.quote_plus(TEXT),
confidence=CONFIDENCE,
support=SUPPORT
)
HEADERS = {'Accept': 'application/json'}
sparql = SPARQLWrapper("http://dbpedia.org/sparql")
all_urls = []
r = requests.get(url=REQUEST, headers=HEADERS)
response = r.json()
resources = response['Resources']
for res in resources:
all_urls.append(res['@URI'])
for url in all_urls:
sparql.setQuery("""
SELECT * WHERE {<"""
+url+
""">skos:broader|dct:subject ?resource
}
""")
sparql.setReturnFormat(JSON)
results = sparql.query().convert()
for result in results["results"]["bindings"]:
print('resource ---- ', result['resource']['value'])
Я рад предоставить больше примеров, если это необходимо.
1 ответ
Кажется, вы пытаетесь найти категории Википедии, относящиеся к данному абзацу.
Незначительные предложения
Во-первых, я бы посоветовал вам выполнить один запрос, собирая результаты DBpedia Spotlight в VALUES
например, таким образом:
values = '(<{0}>)'.format('>) (<'.join(all_urls))
Во-вторых, если вы говорите об иерархии тем, вы должны использовать пути к свойствам SPARQL 1.1.
Эти два предложения слегка несовместимы. Виртуоз очень неэффективен, когда запрос содержит несколько начальных точек (т.е. VALUES
) и пути произвольной длины (т.е. *
а также +
операторы).
Здесь ниже я использую dct:subject/skos:broader
путь свойства, то есть получение категорий "следующего уровня".
Подход 1
Первый способ - упорядочить ресурсы по их общей популярности, например, по их PageRank:
values = '(<{0}>)'.format('>) (<'.join(all_urls))
sparql.setQuery(
"""PREFIX vrank:<http://purl.org/voc/vrank#>
SELECT DISTINCT ?resource ?rank
FROM <http://dbpedia.org>
FROM <http://people.aifb.kit.edu/ath/#DBpedia_PageRank>
WHERE {
VALUES (?s) {""" + values +
""" }
?s dct:subject/skos:broader ?resource .
?resource vrank:hasRank/vrank:rankValue ?rank.
} ORDER BY DESC(?rank)
LIMIT 10
""")
Результаты:
dbc:Member_states_of_the_United_Nations
dbc:Country_subdivisions_of_Europe
dbc:Republics
dbc:Demography
dbc:Population
dbc:Countries_in_Europe
dbc:Third-level_administrative_country_subdivisions
dbc:International_law
dbc:Former_countries_in_Europe
dbc:History_of_the_Soviet_Union_and_Soviet_Russia
Подход 2
Второй способ состоит в том, чтобы вычислить частоту категории данного текста...
values = '(<{0}>)'.format('>) (<'.join(all_urls))
sparql.setQuery(
"""SELECT ?resource count(?resource) AS ?count WHERE {
VALUES (?s) {""" + values +
""" }
?s dct:subject ?resource
} GROUP BY ?resource
# https://github.com/openlink/virtuoso-opensource/issues/254
HAVING (count(?resource) > 1)
ORDER BY DESC(count(?resource))
LIMIT 10
""")
Результаты:
dbc:Wars_by_country
dbc:Wars_involving_the_states_and_peoples_of_Europe
dbc:Wars_involving_the_states_and_peoples_of_Asia
dbc:Wars_involving_the_states_and_peoples_of_North_America
dbc:20th_century_in_Germany
dbc:Modern_history_of_Germany
dbc:Wars_involving_the_Balkans
dbc:Decades_in_Germany
dbc:Modern_Europe
dbc:Wars_involving_the_states_and_peoples_of_South_America
С dct:subject
вместо dct:subject/skos:broader
, результаты лучше:
dbc:Former_polities_of_the_Cold_War
dbc:Former_republics
dbc:States_and_territories_established_in_1949
dbc:20th_century_in_Germany_by_period
dbc:1930s_in_Germany
dbc:Modern_history_of_Germany
dbc:1990_disestablishments_in_West_Germany
dbc:1933_disestablishments_in_Germany
dbc:1949_establishments_in_West_Germany
dbc:1949_establishments_in_Germany
Заключение
Результаты не очень хорошие. Я вижу две причины: категории DBpedia довольно случайны, инструменты довольно примитивны. Возможно, можно добиться лучших результатов, комбинируя подходы 1 и 2. В любом случае, необходимы эксперименты с большим корпусом.