Средняя оценка каждой строки pd.Serie на основе ее содержимого, отображаемого через другую серию оценок

У меня есть (очень большая) серия, содержащая ключевые слова (каждая строка содержит несколько ключевых слов, разделенных знаком '-', например

In[5]: word_series
Out[5]: 
0    the-cat-is-pink
1           blue-sea
2      best-job-ever
dtype: object

У меня есть еще одна серия, которая содержит атрибуты оценки для каждого слова (слова - это индекс, оценки - значения), например:

In[7]: all_scores
Out[7]: 
the     0.34
cat     0.56
best    0.01
ever    0.77
is      0.12
pink    0.34
job     0.01
sea     0.87
blue    0.65
dtype: float64

Все слова из моей word_series появляются в моих оценках. Я пытаюсь найти самый быстрый способ присвоить оценку каждой строке word_series на основе средней оценки каждого из ее слов из all_scores. Если строка не указана, оценка должна быть средним значением.

Я пробовал применить этот способ, но это было слишком медленно.

scores = word_series.apply(
        lambda x: all_scores[x.split('-')].mean()).fillna(
        all_scores.mean())

Затем я подумал, что могу разделить all_words на столбцы с помощью str.replace и, возможно, выполнить операцию типа умножения матриц, используя эту новую матрицу M и мои слова, такие как M.mul (all_scores), где каждая строка в M будет сопоставлена ​​со значениями на основе индекса из all_scores. Это был бы первый шаг, чтобы получить среднее значение, которое я мог бы затем разделить на количество нон-на в каждой строке

In[9]: all_words.str.split('-', expand=True)
Out[9]: 
      0    1     2     3
0   the  cat    is  pink
1  blue  sea  None  None
2  best  job  ever  None

Возможна ли такая операция? Или есть еще один быстрый способ добиться этого?


person tishu    schedule 22.02.2019    source источник


Ответы (2)


Работа со строковыми данными в pandas выполняется медленно, поэтому используйте понимание списка с помощью map Series и mean:

from statistics import mean

L = [mean(all_scores.get(y) for y in x.split('-')) for x in word_series]
a = pd.Series(L, index=word_series.index)
print (a)

0    0.340000
1    0.760000
2    0.263333
dtype: float64

Or:

def mean(a):
    return sum(a) / len(a)

L = [mean([all_scores.get(y) for y in x.split('-')]) for x in word_series]
a = pd.Series(L, index=word_series.index)

Если возможно, некоторые значения не совпадают, добавьте параметр np.nan в get и используйте numpy.nanmean :

L = [np.nanmean([all_scores.get(y, np.nan) for y in x.split('-')]) for x in word_series]
a = pd.Series(L, index=word_series.index)

Or:

def mean(a):
    return sum(a) / len(a)

L = [mean([all_scores.get(y, np.nan) for y in x.split('-') if y in all_scores.index]) 
      for x in word_series]
person jezrael    schedule 22.02.2019

вот способ

печать (а)

             words
0  the-cat-is-pink
1         blue-sea
2    best-job-ever

печать (б)

      all_scores
the         0.34
cat         0.56
best        0.01
ever        0.77
is          0.12
pink        0.34
job         0.01
sea         0.87
blue        0.65

b = b.reset_index()

печать (б)

  index  all_scores
0   the        0.34
1   cat        0.56
2  best        0.01
3  ever        0.77
4    is        0.12
5  pink        0.34
6   job        0.01
7   sea        0.87
8  blue        0.65

a['score'] = a['words'].str.split('-').apply(lambda x: sum([b[b['index'] == w].reset_index()['all_scores'][0] for w in x])/len(x))

вывод

             words     score
0  the-cat-is-pink  0.340000
1         blue-sea  0.760000
2    best-job-ever  0.263333
person iamklaus    schedule 22.02.2019
comment
@tishu хочет mean, а не sum - person Nihal; 22.02.2019