Наиболее эффективный в вычислительном отношении способ сопоставления уникального числа с каждой уникальной строкой в ​​столбце списков - PullRequest
0 голосов
/ 10 сентября 2018

Это продолжение вопроса

Как сопоставить уникальный номер каждой уникальной строке в столбце списков

Что спрашивает, как сопоставить уникальный номер с элементами в нескольких столбцах панд, содержащих списки.

Представленное решение кажется очень медленным, когда количество предметов (общее количество предметов в столбце A и столбце B) находится в диапазоне ~ 40 миллионов. Я нашел несколько способов, позволяющих назначать уникальные номера наборам данных на ~ 40 миллионов элементов быстрее, но ни один из них не подходит для ситуации с несколькими столбцами, один из которых содержит список.

Вот минимальный пример и решение по ссылке выше:

Настройка фрейма данных

df = pd.DataFrame(data={'A': ['2f4', '1k1', 'nmk'], 'B': ['x', 'y', 'z']})
df.at[0, 'B'] = ['jki', 'gg4', 'k6k']
df.at[1, 'B'] = ['2f4', 'gg4', 'g24']
df.at[2, 'B'] = ['1k1', 'g24', '1k1', 'pir']

df

     A                     B
0  2f4       [jki, gg4, k6k]
1  1k1       [2f4, gg4, g24]
2  nmk  [1k1, g24, 1k1, pir]

Решение

i, u = pd.factorize([*df.A, *np.concatenate(df.B)])
l = df.B.str.len()[:-1].cumsum()
n = len(df)

df.assign(MappedA=i[:n], MappedB=np.split(i[n:], l))

     A                     B  MappedA       MappedB
0  2f4       [jki, gg4, k6k]        0     [3, 4, 5]
1  1k1       [2f4, gg4, g24]        1     [0, 4, 6]
2  nmk  [1k1, g24, 1k1, pir]        2  [1, 6, 1, 7]

Я пытаюсь увидеть, есть ли более вычислительно эффективные решения. Я подозреваю, что это так, потому что существуют методы, которые могут присвоить уникальные номера ~ 40 миллионам элементов за несколько минут (где, как показано выше, решение никогда не завершается).

Вот одно из таких решений

mapping = {k: v for v, k in enumerate(df.A.unique())}  
df['MappedA'] = df.A.map(mapping)

Мне интересно, есть ли способ как-то применить это к моей ситуации, когда элементы в столбце A и столбце B отображаются на уникальные числа, начиная с 0, а элементы в столбце A получают первые числа, а затем присваивают оставшиеся уникальные предметы в столбце B.

Edit:

Пользователь упомянул, что pandas - не самый эффективный в вычислительном отношении способ работы со списками строк. Я могу преобразовать это в массив Numpy через

numpyArray = df.values

Так что, если есть способ работать с решением с использованием массивов, он может быть очень легко реализован.

1 Ответ

0 голосов
/ 10 сентября 2018

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

a = df.A.values
b = np.concatenate(df.B.values)
i, u = pd.factorize(np.append(a, b))
l = np.array([*map(len, df.B)])[:-1].cumsum()
n = len(df)

df.assign(MappedA=i[:n], MappedB=np.split(i[n:], l))

Для большего df

df = pd.concat([df] * 10000, ignore_index=True)

%%timeit
i, u = pd.factorize([*df.A, *np.concatenate(df.B)])
l = df.B.str.len()[:-1].cumsum()
n = len(df)

df.assign(MappedA=i[:n], MappedB=np.split(i[n:], l))

# 1 loop, best of 3: 506 ms per loop

%%timeit
a = df.A.values
b = np.concatenate(df.B.values)
i, u = pd.factorize(np.append(a, b))
l = np.array([*map(len, df.B)])[:-1].cumsum()
n = len(df)

df.assign(MappedA=i[:n], MappedB=np.split(i[n:], l))

# 10 loops, best of 3: 95.1 ms per loop

Это дает нам 5-кратное улучшение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...