у меня есть dataframe с каждой строкой, имеющей значение списка.
id list_of_value
0 ['a','b','c']
1 ['d','b','c']
2 ['a','b','c']
3 ['a','b','c']
я должен сделать подсчет очков с одной строкой и против всех других строк
Например:
Step 1: Take value of id 0: ['a','b','c'],
Step 2: find the intersection between id 0 and id 1 ,
resultant = ['b','c']
Step 3: Score Calculation => resultant.size / id.size
повторите шаг 2,3 между идентификаторами 0 и 1,2,3, аналогично для всех идентификаторов.
и создать кадр данных N x N; такие как это:
- 0 1 2 3
0 1 0.6 1 1
1 1 1 1 1
2 1 1 1 1
3 1 1 1 1
Прямо сейчас мой код имеет только один цикл for:
def scoreCalc(x,queryTData):
#mathematical calculation
commonTData = np.intersect1d(np.array(x),queryTData)
return commonTData.size/queryTData.size
ids = list(df['feed_id'])
dfSim = pd.DataFrame()
for indexQFID in range(len(ids)):
queryTData = np.array(df.loc[df['id'] == ids[indexQFID]]['list_of_value'].values.tolist())
dfSim[segmentDfFeedIds[indexQFID]] = segmentDf['list_of_value'].apply(scoreCalc,args=(queryTData,))
Есть лучший способ сделать это? Могу ли я просто написать одну функцию apply вместо выполнения итерации цикла for. я могу сделать это быстрее?
list_of_value
?list_of_value
. Я имею в виду, в целом, по всем рядам.Ответы:
Если ваши данные не слишком велики, вы можете использовать их
get_dummies
для кодирования значений и умножения матриц:Вывод:
Обновление : вот краткое объяснение кода. Основная идея состоит в том, чтобы превратить данные списки в одно горячее кодирование:
Получив это, размер пересечения двух строк, скажем,
0
и1
является просто их точечным произведением, потому что символ принадлежит обеим строкам тогда и только тогда, когда он представлен1
в обеих.Имея это в виду, первое использование
превратить каждую ячейку в серию и объединить все эти серии. Вывод:
Теперь мы используем
pd.get_dummies
этот ряд, чтобы превратить его в кадр данных с горячим кодированием:Как видите, у каждого значения есть свой ряд. Поскольку мы хотим объединить те, которые принадлежат одной и той же исходной строке, в одну строку, мы можем просто сложить их по исходному индексу. таким образом
дает двоичный кодированный фрейм данных, который мы хотим. Следующая строка
это как ваша логика:
s.dot(s.T)
вычисляет точечные произведения по строкам, а затем.div(s.sum(1))
делит счетчики по строкам.источник
12k x 12k
. Должно быть хорошо, если у вас есть несколько сотен уникальных значений.Попробуй это
Вывод
Вы также можете сделать это следующим образом
источник
Используйте понимание вложенного списка в списке множества
s_list
. В пределах понимания списка используйтеintersection
операцию, чтобы проверить перекрытие и получить длину каждого результата. Наконец, создайте фрейм данных и разделите его на длину каждого списка вdf.list_of_value
Если в каждом списке есть повторяющиеся значения, вы должны использовать
collections.Counter
вместоset
. Я изменил пример данных с id = 0 на['a','a','c']
и id = 1 на['d','b','a']
источник
обновленный
Поскольку предложено много вариантов решения, представляется целесообразным провести анализ времени. Я сгенерировал некоторые случайные данные с 12-тысячными строками в соответствии с запросом OP, сохранив 3 элемента в наборе, но увеличив размер алфавита, доступного для заполнения наборов. Это может быть скорректировано, чтобы соответствовать фактическим данным.
Дайте мне знать, если у вас есть решение, которое вы хотели бы проверить или обновить.
Настроить
Текущий Победитель
Соперники
Исходное сообщение с деталями решения
Это можно сделать
pandas
самостоятельно.Как указывали другие ответы, первый шаг - распаковать данные в более длинную форму.
Из этой таблицы можно рассчитать количество идентификаторов.
И затем наступает самообъединение, которое происходит в
value
столбце. Это объединяет идентификаторы один раз для каждого пересекающегося значения, поэтому парные идентификаторы могут быть подсчитаны, чтобы получить размеры пересечения.Эти два затем могут быть объединены и подсчитана оценка.
Если вы предпочитаете матричную форму, это возможно с
pivot
. Это будет гораздо большее представление, если данные редки.источник
Это решение будет работать эффективно с любым размером данных и любого рода ценностей в вашем
list
говорят егоstr
илиint
или иным образом , а также заботиться о повторяющихся значений , если таковые имеются.В этом случае понимание списка работает лучше, потому что ему не нужно загружать атрибут добавления списка и вызывать его как функцию на каждой итерации. Другими словами и в целом, списки работают быстрее, потому что приостановка и возобновление фрейма функции или нескольких функций в других случаях медленнее, чем создание списка по требованию.
Использование понимания списка вместо цикла, который не создает список, бессмысленное накопление списка бессмысленных значений и затем выбрасывание списка, часто медленнее из-за накладных расходов на создание и расширение списка.
Результат:
Время исполнения:
источник
Вы можете преобразовать список в набор и использовать функцию пересечения для проверки наложения:
(как вы и просили, используется только 1 функция применения)
источник
Я бы использовал,
product
чтобы получить все комбинации. Тогда мы можем проверить сnumpy.isin
иnumpy.mean
:Образец времени
источник
Должно быть быстро, также рассмотрите дубликат в списке
источник
Да! Мы ищем декартово произведение здесь, которое дано в этом ответе. Это может быть достигнуто без цикла for или понимания списка
Давайте добавим новое повторное значение в наш фрейм данных,
df
чтобы оно выглядело так:Далее слиться с собой
Вот как выглядит объединенная рамка:
Затем мы применяем желаемую функцию к каждой строке, используя
axis=1
Изменение этого, чтобы получить значения в нужном формате
Надеюсь это поможет :)
источник