Есть ли более быстрый (непонятный?) Способ объединить столбцы pandas df int в строку с разделением точками без TypeError - PullRequest
0 голосов
/ 03 марта 2019

Я хочу объединить два столбца типа int, чтобы создать новый столбец str, разделенный точками.У меня есть один способ, который работает, но если есть более быстрый способ, это поможет.Я также попробовал предложение, которое я нашел в другом ответе на SO, который выдает ошибку.

Это работает:

df3 = pd.DataFrame({'job_number': [3913291, 3887250, 3913041],
                   'task_number': [38544, 0, 1]})
df3['filename'] = df3['job_number'].astype(str) + '.' + df3['task_number'].astype(str)

0    3913291.38544
1    3887250.0    
2    3913041.1

Этот ответ на аналогичный вопрос предполагает"тупой" способ, используя .values.astype(str), но я еще не заставил его работать.Здесь я запускаю его без включения разделителя точек:

df3['job_number'].values.astype(int).astype(str) + df3['task_number'].astype(int).astype(str)

0    391329138544
1    38872500    
2    39130411 

Но когда я включаю разделитель точек, я получаю ошибку:

df3['job_number'].values.astype(int).astype(str) + '.' + df3['task_number'].astype(int).astype(str)

TypeError: ufunc 'add' did not contain a loop with signature matching types dtype('<U11') dtype('<U11') dtype('<U11')

Результат, который я хочу получить:

0    3913291.38544
1    3887250.0    
2    3913041.1

Ответы [ 3 ]

0 голосов
/ 03 марта 2019

Вы можете использовать понимание списка:

df3["filename"] = ['.'.join(i) for i in 
                          zip(df3["job_number"].map(str),df3["task_number"].map(str))]

Если использовать python 3.6+, самое быстрое решение с f-string s:

df3["filename2"] = [f'{i}.{j}' for i,j in zip(df3["job_number"],df3["task_number"])]

Производительность в 30 тыс. Строк:

df3 = pd.DataFrame({'job_number': [3913291, 3887250, 3913041],
                   'task_number': [38544, 0, 1]})
df3 = pd.concat([df3] * 10000, ignore_index=True)


In [64]: %%timeit
    ...: df3["filename2"] = [f'{i}.{j}' for i,j in zip(df3["job_number"],df3["task_number"])]
    ...: 
20.5 ms ± 226 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [65]: %%timeit
    ...: df3["filename3"] = ['.'.join(i) for i in zip(df3["job_number"].map(str),df3["task_number"].map(str))]
    ...: 
30.9 ms ± 189 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [66]: %%timeit
    ...: df3["filename4"] = df3.T.apply(lambda x: str(x[0]) + '.' + str(x[1]))
    ...: 
1.7 s ± 31.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [67]: %%timeit
    ...: df3['dummy'] ='.'
    ...: res = df3['job_number'].values.astype(str) + df3['dummy'] + df3['task_number'].values.astype(str)
    ...: df3.drop(columns=['dummy'], inplace=True)
    ...: 
73.6 ms ± 1.23 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Но также очень быстро оригинальное решение:

In [73]: %%timeit
    ...: df3['filename'] = df3['job_number'].astype(str) + '.' + df3['task_number'].astype(str)
48.3 ms ± 872 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

С небольшой модификацией - с использованием map вместо astype:

In [76]: %%timeit
    ...: df3['filename'] = df3['job_number'].map(str) + '.' + df3['task_number'].map(str)
    ...: 
26 ms ± 676 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
0 голосов
/ 03 марта 2019

Методы в порядке %%timeit результатов

Я рассчитал все предложенные методы и еще несколько на двух фреймах данных.Вот временные результаты для предложенных методов (спасибо @meW и @jezrael).Если я пропустил или у вас есть другой, дайте мне знать, и я добавлю это.

Для каждого метода показаны два момента времени: сначала для обработки 3 строк в примере df, а затем для обработки 57K строк в другом df.Время может варьироваться в другой системе.Решения, которые включают TEST['dot'] в строке конкатенации, требуют этого столбца в df: добавьте его с помощью TEST['dot'] = '.'.

Исходный метод (все еще самый быстрый):

.astype (str), +, '.'

%%timeit
TEST['filename'] = TEST['job_number'].astype(str) + '.' + TEST['task_number'].astype(str)
# 553 µs ± 6.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) on 3 rows
# 69.6 ms ± 876 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) on 57K rows

Предлагаемые методы и несколько перестановок на них:

.astype (int) .astype (str), +, '.'

%%timeit
TEST['filename'] = TEST['job_number'].astype(int).astype(str) + '.' + TEST['task_number'].astype(int).astype(str)
# 553 µs ± 6.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) on 3 rows
# 70.2 ms ± 739 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) on 57K rows

.values.astype (int) .astype (str), +, TEST ['dot']

%%timeit
TEST['filename'] = TEST['job_number'].values.astype(int).astype(str) + TEST['dot'] + TEST['task_number'].values.astype(int).astype(str)
# 221 µs ± 5.93 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) on 3 rows
# 82.3 ms ± 743 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) on 57K rows

.values.astype (str), +, TEST ['dot']

%%timeit
TEST["filename"] = TEST['job_number'].values.astype(str) + TEST['dot'] + TEST['task_number'].values.astype(str)
# 221 µs ± 5.93 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) on 3 rows
# 92.8 ms ± 1.21 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) on 57K rows

'.' Join (), понимание списка, .values.astype (str)

%%timeit
TEST["filename"] = ['.'.join(i) for i in TEST[["job_number",'task_number']].values.astype(str)]
# 743 µs ± 19.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) on 3 rows
# 147 ms ± 532 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) on 57K rows

f-строка, понимание списка, .values.astype (str)

%%timeit
TEST["filename2"] = [f'{i}.{j}' for i,j in TEST[["job_number",'task_number']].values.astype(str)]
# 642 µs ± 27.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) on 3 rows
# 167 ms ± 3.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) on 57K rows

'.'.join (), zip, понимание списка, .map (str)

%%timeit
TEST["filename"] = ['.'.join(i) for i in 
                          zip(TEST["job_number"].map(str), TEST["task_number"].map(str))]
# 512 µs ± 5.74 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) on 3 rows
# 181 ms ± 4.17 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) on 57K rows

apply (лямбда, str (x [2]), +,'. ')

%%timeit
TEST['filename'] = TEST.T.apply(lambda x: str(x[2]) + '.' + str(x[10]))
# 735 µs ± 13.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) on 3 rows
# 2.69 s ± 18.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) on 57K rows

Если вы видите способ улучшить что-либо из этого, пожалуйста, дайте мне знать, и я добавлю в список!

0 голосов
/ 03 марта 2019

Для сравнения данных методов с другими доступными методами обратитесь к ответу @Jezrael.

Метод 1

Чтобы добавить фиктивный столбец, содержащий ., используйте его при обработке, а затем отбросьте его:

%%timeit
df3['dummy'] ='.'
res = df3['job_number'].values.astype(str) + df3['dummy'] + df3['task_number'].values.astype(str)
df3.drop(columns=['dummy'], inplace=True)

1.31 ms ± 41.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Для расширения метода 1, если вы исключите время обработки создания пустого столбца и его отбрасывания, то это лучшее, что вы получите -

%%timeit
df3['job_number'].values.astype(str) + df3['dummy'] + df3['task_number'].values.astype(str)

286 µs ± 15.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Метод 2

Использование apply

%timeit df3.T.apply(lambda x: str(x[0]) + '.' + str(x[1]))

883 µs ± 22 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...