2017-01-21 3 views
3

У меня есть таблица, которая выглядит следующим образом:панды: группировка по ключу кластер запутанных строк

company_id,company_name 
1,Amazon 
1,Amazon Ltd 
2,Google 
1,Amazon 
2,Gogle 
3,Facebook Ltd 
3,Facebook LTD 
1,AMAZON 
1,AMAZON LTD 
2,GOOGLE 
3,Facebook 
3,Face book 

Так у меня есть уникальный идентификатор для каждой компании, но их текстовое представление отличается. То, что я стремиться, чтобы устранить эти несоответствия и что-то вдоль линий:

company_id,company_name 
1,Amazon 
1,Amazon 
2,Google 
1,Amazon 
2,Google 
3,Facebook 
3,Facebook 
1,Amazon 
1,Amazon 
2,Google 
3,Facebook 
3,Facebook 

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

Моим решением было создать хэш-карту уникальных комбо id -> name, а затем заменить их на основе этих. Что-то вдоль линий:

dd = df.drop_duplicates().set_index('company_id').to_dict()['company_name'] 
df.company_name = df.company_id 
df.company_name = df.company_name.replace(dd) 

Который работает отлично на небольших наборах, но это становится довольно медленными и памятью неэффективно из-за большой хэш-карту он создает.

Я также попытался groupby на основе company_id и заменяя все company_name S внутри каждой группы по случайной величины, но я не мог изменить основную dataframe (без .loc ИНГ его, что вдвойне неэффективно) ,

Последний способ, который возникает из-за необходимости создать отдельный кадр с уникальными значениями (df.drop_duplicates('company_id')) и объединить его с исходным фреймом на основе company_id, но это также не звучит ужасно эффективно.

+0

Ваше решение кажется прекрасным для меня. 'df.company_name = df.company_name.replace (dd)' здесь вместо 'replace', если вы используете' map', это будет намного быстрее. Однако вам нужны эти пары, независимо от того, что я не знаю, как вы решите проблему с памятью. Вы уверены, что это проблема? Сколько уникальных идентификаторов у вас есть? – ayhan

+1

Вам не нужно '.loc' переназначать их обратно в базовый' DF'. 'Groupby.transform' позаботится об этом. –

ответ

3

Я проверил свое решение на достаточно большой DataFrame с помощью map и это выглядит довольно эффективно:

prng = np.random.RandomState(0) 
df = pd.DataFrame({'company_id': prng.randint(10**6, size=10**7), 
        'company_name': prng.rand(10**7).astype('str')}) 
# It has 10m unique identifiers each having 10 entries on average 
# ranges from 1 to 28. 

df.head() 
    company_id   company_name 
0  985772 0.4097176168442743 
1  305711 0.506659503051052 
2  435829 0.45049621797963846 
3  117952 0.21756825314220174 
4  963395 0.07977409062048224 

Теперь вы можете создать картограф между company_id и первым вхождением company_name для этого ID:

%%timeit 
mapper = df.drop_duplicates(subset='company_id').set_index('company_id')['company_name'] 
df['company_id'].map(mapper) 
1 loop, best of 3: 1.86 s per loop 

Как Nickil Maveli mentioned, transform также возможность альт поджилки производительность для данного набора данных я создал не так хорошо, как карта:

%timeit df.groupby('company_id')['company_name'].transform('first') 
1 loop, best of 3: 2.33 s per loop 

.loc выглядит довольно неэффективен:

%timeit df.groupby('company_id').first().loc[df.company_id] 
1 loop, best of 3: 26.4 s per loop 

В общем, вы могли бы быть лучше использовать categoricals для этого типа данных , См. Другое обсуждение here.

0

Вы можете сгруппировать по company_id и получить доступ к компании ID:

df.groupby('company_id').first().loc[df.company_id] 

Результат:

enter image description here

Если вы хотите, чтобы в качестве колонки, сбросьте индекс:

df.groupby('company_id').first().loc[df.company_id].reset_index() 

Результат:

enter image description here