Как создать матрицу дружбы для 1,5 миллионов пользователей в python?

Моя задача - создать матрицу дружбы (пользовательскую матрицу), значения которой равны 1, если пользователи являются друзьями и 0, если нет. Мой .csv-файл имеет 1,5 миллиона строк, поэтому я создаю следующие небольшие csv для проверки моего алгоритма:

user_id              friends
   Elena          Peter, John
   Peter          Elena, John
   John           Elena, Peter, Chris
   Chris          John

Для этого небольшого csv мой код работает хорошо:

%matplotlib inline

import pandas as pd
import seaborn as sns
import numpy as np

from scipy import sparse

sns.set(style="darkgrid")

user_filepath = 'H:\YelpData\test.csv' # this is my little test file

df = pd.read_csv(user_filepath, usecols=['user_id','friends'])

def Convert_String_To_List(string):
    if string!="None":
        li = list(string.split(", ")) 
    else:
        li = []
    return li 

friend_map = {}

for i in range(len(df)): #storing friendships in map
    friend_map[df['user_id'][i]] = Convert_String_To_List(df['friends'][i])

users = sorted(friend_map.keys()) 
user_indices = dict(zip(users, range(len(users)))) #giving indices for users

#and now the sparsity matrix:

row_ind = [] #row indices, where the value is 1
col_ind = [] #col indices, where the value is 1
data = []    # value 1

for user in users:
    for barat in baratok[user]:
        row_ind.append(user_indices[user])
        col_ind.append(user_indices[barat])

for i in range(len(row_ind)):
    data.append(1)

mat_coo = sparse.coo_matrix((data, (row_ind, col_ind)))

friend_matrix = mat_coo.toarray() #this friendship matrix is good for the little csv file

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

Есть ли решение для этого?

Всего 2 ответа


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

Это полный подход pandas зависимости от ваших данных.

import pandas as pd

_series = df1.friends.apply(lambda x: pd.Series(x.split(', '))).unstack().dropna()
data = pd.Series(_series.values, index=_series.index.droplevel(0))
pd.get_dummies(data).groupby('user_id').sum()

Выход

        Chris   Elena   John    Peter
user_id             
Chris   0          0    1        0
Elena   0          0    1        1
John    1          1    0        1
Peter   0          1    1        0

BTW, это может быть дополнительно оптимизировано, и с помощью pandas вы избегаете использования дорогостоящих для циклов памяти, и вы можете использовать chunksize для chunksize ваших данных для дальнейшей оптимизации.


Я думаю, вы не должны хранить строку повторно. Вам нужно составить список имен и сохранить индекс имени, а не само имя. Эта часть кода:

friend_map[df['user_id'][i]] = Convert_String_To_List(df['friends'][i])

может быть изменено. Если у вас есть список пользователей,

users = [....] # read from csv
friend_list = Convert_String_To_List(df['friends'][i])
friend_list_idxs = Get_Idx_of_Friends(users,friend_list) #look up table users
friend_map[df['user_id'][i]] = friend_list_idxs

Таким образом, вам не нужно будет хранить одну и ту же строку повторно.

Допустим, у вас 10 миллионов друзей, вам нужно будет хранить 10 МБ памяти.


Есть идеи?

10000