Подсчет количества уникальных соавторов в кадре данных - PullRequest
0 голосов
/ 12 февраля 2019

У меня действительно большой массив данных с идентификаторами книг и именами людей, которые совместно написали каждую книгу.Я хочу подсчитать, сколько «уникальных» соавторов работал с каждым автором за всю его всю карьеру .

Например:

BookID   Author
  1         John
  1         Alex
  1         Jenna
  2         John
  2         Alex
  3         John
  4         Alex
  4         Mary
  4         Max

Ожидаемый результатбыло бы (то, что между скобками не требуется, но я поставил это там, чтобы лучше обосновать, я просто хочу число):

Author     Num_Unique_CoAuthors
 John           2                    (Alex and Jenna)
 Alex           4                    (John, Jenna, Mary and Max)
 Jenna          2                    (Alex and John)
 Mary           2                    (Alex and Max)
 Max            2                    (Alex and Mary)

Ответы [ 3 ]

0 голосов
/ 12 февраля 2019

Сначала создайте set s для каждой группы в новом столбце, затем получите разницу с столбцом Author, удалите пустые наборы на boolean indexing и последним сведите значения в новые наборы для уникальной, последней длины получения:

df = df.join(df.groupby('BookID')['Author'].apply(set).rename('new'), 'BookID')

df['new'] = [b - set([a]) for a, b in zip(df['Author'], df['new'])]

df = (df[df['new'].astype(bool)].groupby('Author')['new']
          .apply(lambda x: tuple(set([z for y in x for z in y])))
          .to_frame())

df.insert(0, 'Num_Unique_CoAuthors', df['new'].str.len())
print (df)
        Num_Unique_CoAuthors                       new
Author                                                
Alex                       4  (Max, John, Jenna, Mary)
Jenna                      2              (John, Alex)
John                       2             (Jenna, Alex)
Mary                       2               (Max, Alex)
Max                        2              (Mary, Alex)
0 голосов
/ 12 февраля 2019

У меня есть альтернативное решение.

  1. Присоединиться к BookID
  2. Создать матрицу смежности, используя crosstab
  3. Tallyвверх по счетчикам вдоль строк, не считая автора строки.

>>> df_merge = df.merge(df, on='BookID')
>>> ctdf = pd.crosstab(df_merge.Author_x, df_merge.Author_y, aggfunc='max', values=[1] * len(df_merge)).fillna(0)
>>> ctdf
Author_y  Alex  Jenna  John  Mary  Max
Author_x
Alex       1.0    1.0   1.0   1.0  1.0
Jenna      1.0    1.0   1.0   0.0  0.0
John       1.0    1.0   1.0   0.0  0.0
Mary       1.0    0.0   0.0   1.0  1.0
Max        1.0    0.0   0.0   1.0  1.0
>>> ctdf.apply(lambda x: sum([*x]) - 1)
Author_y
Alex     4.0
Jenna    2.0
John     2.0
Mary     2.0
Max      2.0
dtype: float64
0 голосов
/ 12 февраля 2019

Другой подход

Первая группа в BookID и список всех авторов в каждой книге (т.е. список всех авторов в группе)

combos = df.groupby('BookID').agg(lambda x: list(x)).reset_index(drop=False)
print(combos)
   BookID               Author
0       1  [John, Alex, Jenna]
1       2         [John, Alex]
2       3               [John]
3       4    [Alex, Mary, Max]

Далее, объединить сОсновные данные, BookID, для получения всех авторов для каждого автора

merged = combos.merge(df, how='inner', on='BookID')
print(merged)
   BookID             Author_x Author_y
0       1  [John, Alex, Jenna]     John
1       1  [John, Alex, Jenna]     Alex
2       1  [John, Alex, Jenna]    Jenna
3       2         [John, Alex]     John
4       2         [John, Alex]     Alex
5       3               [John]     John
6       4    [Alex, Mary, Max]     Alex
7       4    [Alex, Mary, Max]     Mary
8       4    [Alex, Mary, Max]      Max

Author_x - полный список авторов, включающий Author_y.Теперь можно сравнивать полный список авторов (Author_x) с каждым отдельным / уникальным автором (Author_y), используя следующий подход

  1. Создание дикта, ключи которого уникальны Author_y значения (то есть уникальные авторы) и значения являются пустыми списками
  2. Итерация по каждой паре ключ-значение в dict
  3. слайд объединенного кадра данных с шага выше с использованием столбца Author_y;это дает всех авторов для автора в ключе dict
  4. из среза, получить список всех авторов (Author_x) в виде сведенного списка
  5. расширить пустой список с помощью разница между сплющенным списком (все авторы) и ключом dict
d = {auth:[] for auth in df['Author'].unique()}
for k,v in d.items():
    all_auths = merged[merged['Author_y']==k]['Author_x'].values.tolist()
    auths = [coauths for nested in all_auths for coauths in nested]
    v.extend(list(set(auths) - set([k])))

Наконец, поместите в DataFrame и посчитайте ненулевые значения для строки

cnames = ['coauth'+str(k) for k in range(1,len(d))]
df_summary = pd.DataFrame.from_dict(d, orient='index', columns=cnames)
df_summary['Num_Unique_CoAuthors'] = df_summary.shape[1] - df_summary.isna().sum(axis=1)
print(df_summary)
  author coauth1 coauth2 coauth3 coauth4  Num_Unique_CoAuthors
0   John    Alex   Jenna    None    None                     2
1   Alex     Max    John    Mary   Jenna                     4
2  Jenna    John    Alex    None    None                     2
3   Mary     Max    Alex    None    None                     2
4    Max    Alex    Mary    None    None                     2

Расширенный регистр данных

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

Здесьэто фиктивная строка, добавленная к данным, с одним автором

print(df)
   BookID Author
0       1   John
1       1   Alex
2       1  Jenna
3       2   John
4       2   Alex
5       3   John
6       4   Alex
7       4   Mary
8       4    Max
9       5    Tom

А вот вывод

  author coauth1 coauth2 coauth3 coauth4  Num_Unique_CoAuthors
0   John   Jenna    Alex    None    None                     2
1   Alex    Mary    John   Jenna     Max                     4
2  Jenna    John    Alex    None    None                     2
3   Mary     Max    Alex    None    None                     2
4    Max    Mary    Alex    None    None                     2
5    Tom    None    None    None    None                     0

Начальный ответ

Вы пробовали groupby с sum агрегацией

df.groupby(['Author'])['BookID'].sum()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...