Как нормализовать эти данные

Это минимум данных для воспроизведения вопроса:

@prefix rs: <http://example.org/rs#>
@prefix bo: <http://example.org/bo#>
@prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>

rs:user1 rs:hasRated [rs:by "1.0"^^xsd:float ; rs:item bo:animalFarm] .

rs:user2 rs:hasRated [rs:by "0.9"^^xsd:float ; rs:item bo:animalFarm] .

rs:user3 rs:hasRated [rs:by "0.9"^^xsd:float ; rs:item bo:animalFarm] .

rs:user4 rs:hasRated [rs:by "0.5"^^xsd:float ; rs:item bo:book3] .

rs:user5 rs:hasRated [rs:by "0.6"^^xsd:float ; rs:item bo:book3] .

rs:user6 rs:hasRated [rs:by "0.8"^^xsd:float ; rs:item bo:algorithem1] .

rs:user7 rs:hasRated [rs:by "0.9"^^xsd:float ; rs:item bo:algorithem1] .

rs:user8 rs:hasRated [rs:by "0.3"^^xsd:float ; rs:item bo:book4] .

Я хочу нормализовать среднюю оценку для каждого элемента, а также нормализовать количество оценок для каждого элемента

Я могу взять среднее значение оценок для каждого элемента и количество оценок для каждого элемента следующим образом:

PREFIX  bo:   <http://example.org/bo#>
PREFIX  xsd:  <http://www.w3.org/2001/XMLSchema#>
PREFIX  rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX  rs:   <http://example.org/rs#>
select ?item (AVG(?ratingValue) as ?avg) (COUNT(*) as ?count) 
{
    ?user rs:hasRated [ rs:item ?item ;  rs:by ?ratingValue ] .
}
group by ?item 

и результат:

введите здесь описание изображения

Я хотел бы, если это возможно, иметь следующее:

bo:book3                 (0.55/(0.55 + 0.93333334 + 0.85 + 0.3 ))   (2/(2 + 3 + 2 + 1))

и, конечно, то же самое для других предметов.

моя проблема в том, что я не знаю, как сделать сумму и в то же время выполнить деление.

Ваша помощь высоко ценится.

Обновление 1

Я спрашиваю о возможности сделать это, если нет (или если производительность слишком плохая), я получил другое решение


person Ania David    schedule 21.04.2016    source источник
comment
Вы можете использовать Sub-SELECT, который в основном является вашим текущим запросом, и применить агрегацию к его результату во внешнем запросе.   -  person UninformedUser    schedule 21.04.2016
comment
@AKSW, не могли бы вы перефразировать свой комментарий в ответе с вопросом? Я очень сомневаюсь, что подзапрос будет работать, потому что как вы собираетесь делить сумму? у вас может быть сумма (да), но как вы собираетесь это делать (0,55/sumValue)?   -  person Ania David    schedule 21.04.2016
comment
@AniaDavid Я добавил ответ. Полезно попробовать некоторые из этих вещей, чтобы увидеть, работают ли они, прежде чем задавать вопрос о переполнении стека, потому что то, что вы упомянули в комментарии, на самом деле является ответом. Вы делаете: select ?item (avg(?rating_)/?sumAvgRating as ?rating) (count(*)/?countRating as ?percentCount) ....   -  person Joshua Taylor    schedule 21.04.2016


Ответы (1)


В SPARQL данные либо сгруппированы, либо нет. Вы не можете «достучаться» до группы и получить информацию, которая больше, чем сама группа. Это означает, что для этого вам, вероятно, понадобится подзапрос, который получает общие значения отдельно. С данными, которые вы дали:

select ?item
       (avg(?rating_)/?sumAvgRating as ?rating)
       (count(*)/?countRating as ?percentCount)
{
  ?user rs:hasRated [ rs:by ?rating_ ; rs:item ?item ]

  #-- get number of ratings
  { select (count(*) as ?countRating) { ?user rs:hasRated [] }}

  #-- get sum of average ratings
  { select (sum(?avgRating) as ?sumAvgRating) {
      { select (avg(?rating_) as ?avgRating) {
          ?user rs:hasRated [ rs:by ?rating_ ; rs:item ?item ]
        }
        group by ?item
      }
    }
  }
}
group by ?item ?countRating ?sumAvgRating
-----------------------------------------------------------
| item           | rating                  | percentCount |
===========================================================
| bo:book3       | "0.20886075"^^xsd:float | 0.25         |
| bo:book4       | "0.11392405"^^xsd:float | 0.125        |
| bo:algorithem1 | "0.3227848"^^xsd:float  | 0.25         |
| bo:animalFarm  | "0.35443038"^^xsd:float | 0.375        |
-----------------------------------------------------------

Я думаю, что для получения данных, которые вам действительно нужны, и для того, чтобы сделать это без избыточных подзапросов, вам потребуется некоторая постобработка результатов. Я говорю это, потому что на самом деле вы требуете каких-то вычислений, включающих группировку двумя разными способами. Чтобы получить общее количество оценок, вам нужна группа по всем результатам (или, по крайней мере, по группе по некоторым сгруппированным результатам). Чтобы получить средние значения для каждого элемента, вам необходимо сгруппировать элементы. Чтобы получить сумму средних значений, вам нужно сгруппировать сгруппированные данные. Поэтому я не думаю, что вы можете сделать это идеально без избыточных запросов.

Но вы можете некоторую обработку выполнить в запросе. Думаю, я бы получил элементы и их рейтинги, подсчитал рейтинги и суммировал средние значения для каждого элемента, например так:

select ?item (sum(?rating_) as ?sumRating) (count(*) as ?countRating) {
  ?user rs:hasRated [ rs:by ?rating_ ; rs:item ?item ]
}
group by ?item

Причина, по которой я делаю это, а не усреднение оценок, заключается в том, что из подсчета и суммы можно легко восстановить среднее значение (просто разделить сумму на подсчет), и вы можете получить сумму суммы и сумма счетов. Если вы сделаете среднее значение слишком рано, вы не сможете определить, какова на самом деле была сумма всех оценок.

person Joshua Taylor    schedule 21.04.2016
comment
Большое спасибо, дело в том, что вы повторяете один и тот же запрос три раза, а в моей реальной онтологии (реальные данные) мне нужно будет повторить один и тот же запрос три раза, чтобы сделать ваш запрос. - person Ania David; 21.04.2016
comment
@AniaDavid Да, это усложнит проблему. Возможно, имеет смысл получить необработанные данные, а затем выполнить их постобработку в приложении. Сделать все это в запросе сложно. Однако здесь могут быть некоторые варианты, чтобы избежать повторения. Например, когда вы вычисляете среднюю оценку для каждого элемента, вы также можете вычислить количество оценок для элемента, а затем их сумма будет общим количеством оценок. Собственно, это навело меня на мысль... - person Joshua Taylor; 21.04.2016
comment
еще один момент: давайте добавим к запросу, который вычисляет сумму среднего рейтинга, это должно уменьшить количество строк в результатах, но на самом деле из-за подсчета вы все равно получите все элементы в результатах. ты понял меня пожалуйста? попробуйте добавить это `имея (?avgRating ›= 441)`, вы все равно получите все элементы, хотя ни один из них не имеет avgRating больше 441, очевидно - person Ania David; 21.04.2016
comment
@AniaDavid Я немного обновил свой ответ. Реальная проблема заключается в том, что вам нужны: (i) некоторые данные, которые (концептуально) требуют одной группы (общее количество оценок); (ii) некоторые данные, сгруппированные по пунктам (средний рейтинг по каждому пункту); и (iii) некоторые данные, сгруппированные по группам (сумма средних оценок). Чтобы получить эти различные типы групп, вам потребуется либо (а) несколько подзапросов, либо (б) постобработка. - person Joshua Taylor; 22.04.2016
comment
Спасибо, я проверю завтра позже, сейчас мне нужно сделать еще одну новую вещь, и я задам вопрос об этом. - person Ania David; 22.04.2016