Pandas .astype (str) .sum () с разделителем [duplicate]

== сравнивает ссылки на объекты в Java и не является исключением для объектов String.

Для сравнения фактического содержимого объектов (в том числе String) необходимо использовать equals.

Если сравнение двух объектов String с использованием == оказывается true, это связано с тем, что объекты String были интернированы, а виртуальная машина Java имеет несколько ссылки указывают на тот же экземпляр String. Не следует ожидать сравнения одного объекта String, содержащего то же содержимое, что и другой объект String, используя == для оценки как true.

240
задан MaxU 26 November 2017 в 20:36
поделиться

15 ответов

еще один способ сделать это:

df['period'] = df['Year'].astype(str) + df['quarter']

или бит медленнее:

df['period'] = df[['Year','quarter']].astype(str).sum(axis=1)

Давайте проверим его на 200K строках DF:

In [250]: df
Out[250]:
   Year quarter
0  2014      q1
1  2015      q2

In [251]: df = pd.concat([df] * 10**5)

In [252]: df.shape
Out[252]: (200000, 2)

UPDATE: график времени Pandas 0.23.0

UPDATE: новые тайминги с использованием Pandas 0.19.0

Сроки без CPU / GPU (отсортировано от самого быстрого до самого медленного):

In [107]: %timeit df['Year'].astype(str) + df['quarter']
10 loops, best of 3: 131 ms per loop

In [106]: %timeit df['Year'].map(str) + df['quarter']
10 loops, best of 3: 161 ms per loop

In [108]: %timeit df.Year.str.cat(df.quarter)
10 loops, best of 3: 189 ms per loop

In [109]: %timeit df.loc[:, ['Year','quarter']].astype(str).sum(axis=1)
1 loop, best of 3: 567 ms per loop

In [110]: %timeit df[['Year','quarter']].astype(str).sum(axis=1)
1 loop, best of 3: 584 ms per loop

In [111]: %timeit df[['Year','quarter']].apply(lambda x : '{}{}'.format(x[0],x[1]), axis=1)
1 loop, best of 3: 24.7 s per loop

Сроки с использованием оптимизации CPU / GPU:

In [113]: %timeit df['Year'].astype(str) + df['quarter']
10 loops, best of 3: 53.3 ms per loop

In [114]: %timeit df['Year'].map(str) + df['quarter']
10 loops, best of 3: 65.5 ms per loop

In [115]: %timeit df.Year.str.cat(df.quarter)
10 loops, best of 3: 79.9 ms per loop

In [116]: %timeit df.loc[:, ['Year','quarter']].astype(str).sum(axis=1)
1 loop, best of 3: 230 ms per loop

In [117]: %timeit df[['Year','quarter']].astype(str).sum(axis=1)
1 loop, best of 3: 230 ms per loop

In [118]: %timeit df[['Year','quarter']].apply(lambda x : '{}{}'.format(x[0],x[1]), axis=1)
1 loop, best of 3: 9.38 s per loop
110
ответ дан Anton vBR 17 August 2018 в 12:52
поделиться
  • 1
    Какая разница между 261 и 264 в вашем времени? – Anton Protopopov 21 May 2016 в 19:57
  • 2
    @ АнтонПротопопов, видимо, 100 мс из ниоткуда :) – Dennis Golomazov 10 October 2016 в 17:30
  • 3
    @AntonProtopopov, я думаю, это смесь двух таймингов - одна использует оптимизацию CPU / GPU, другая - нет. Я обновил свой ответ и поставил оба набора времени ... – MaxU 10 October 2016 в 17:45
  • 4
    Это использование .sum () не выполняется. Если все столбцы выглядят так, как они могут быть целыми (т.е. являются строковыми формами целых чисел). Вместо этого, кажется, панды преобразуют их обратно в числовое число перед суммированием! – CPBL 25 May 2017 в 13:06
  • 5
    Ничего себе это быстрее ... – Baradwaj Aryasomayajula 4 January 2018 в 23:36
df = pd.DataFrame({'Year': ['2014', '2015'], 'quarter': ['q1', 'q2']})
df['period'] = df[['Year', 'quarter']].apply(lambda x: ''.join(x), axis=1)

Устанавливает этот фрейм данных

   Year quarter  period
0  2014      q1  2014q1
1  2015      q2  2015q2

Этот метод обобщает на произвольное количество столбцов строки, заменив df[['Year', 'quarter']] на любой фрагмент столбца вашего фрейма данных, например. df.iloc[:,0:2].apply(lambda x: ''.join(x), axis=1).

Вы можете проверить дополнительную информацию о методе apply () здесь

143
ответ дан kepy97 17 August 2018 в 12:52
поделиться
  • 1
    lambda x: ''.join(x) просто ''.join, нет? – DSM 19 September 2016 в 11:54
  • 2
    @DSM no. здесь мы берем каждую строку df [['Year', 'quarter']] и передаем ее как ряды, чтобы присоединиться, и присоединяем элементы конкатенации в серии. – Ozgur Ozturk 1 February 2017 в 22:02
  • 3
    @ OzgurOzturk: ​​дело в том, что лямбда-часть конструкции lambda x: ''.join(x) ничего не делает; это похоже на lambda x: sum(x), а не только на sum. – DSM 1 February 2017 в 22:07
  • 4
    Подтвержденный результат при использовании ''.join, т. Е .: df['period'] = df[['Year', 'quarter']].apply(''.join, axis=1). – Max Ghenis 10 October 2017 в 05:30
  • 5
    @Archie join принимает только экземпляры str в итерабельном. Используйте map, чтобы преобразовать их все в str, а затем используйте join. – John Strood 27 March 2018 в 12:51
  • 6

Метод cat() аксессуара .str отлично работает для этого:

>>> import pandas as pd
>>> df = pd.DataFrame([["2014", "q1"], 
...                    ["2015", "q3"]],
...                   columns=('Year', 'Quarter'))
>>> print(df)
   Year Quarter
0  2014      q1
1  2015      q3
>>> df['Period'] = df.Year.str.cat(df.Quarter)
>>> print(df)
   Year Quarter  Period
0  2014      q1  2014q1
1  2015      q3  2015q3

cat() даже позволяет вам добавить разделитель, поэтому для Например, предположим, что у вас есть только целые числа в течение года и периода, вы можете сделать это:

>>> import pandas as pd
>>> df = pd.DataFrame([[2014, 1],
...                    [2015, 3]],
...                   columns=('Year', 'Quarter'))
>>> print(df)
   Year Quarter
0  2014       1
1  2015       3
>>> df['Period'] = df.Year.astype(str).str.cat(df.Quarter.astype(str), sep='q')
>>> print(df)
   Year Quarter  Period
0  2014       1  2014q1
1  2015       3  2015q3

Объединение нескольких столбцов - это просто передача списка серий или данных, содержащих все, кроме первого столбца как параметр str.cat(), вызываемый в первом столбце (серии):

>>> df = pd.DataFrame(
...     [['USA', 'Nevada', 'Las Vegas'],
...      ['Brazil', 'Pernambuco', 'Recife']],
...     columns=['Country', 'State', 'City'],
... )
>>> df['AllTogether'] = df['Country'].str.cat(df[['State', 'City']], sep=' - ')
>>> print(df)
  Country       State       City                   AllTogether
0     USA      Nevada  Las Vegas      USA - Nevada - Las Vegas
1  Brazil  Pernambuco     Recife  Brazil - Pernambuco - Recife
68
ответ дан LeoRochael 17 August 2018 в 12:52
поделиться
  • 1
    Это кажется лучше (возможно, более эффективным), чем lambda или map; также он просто читает самое чистое. – dwanderson 22 May 2016 в 20:31
  • 2
    эффективный метод. – Sayali Sonawane 13 June 2017 в 12:11
  • 3
    @LeoRochael, как это будет распространяться на многие столбцы? – ZakS 23 July 2018 в 09:16
  • 4
    @ZakS, передавая оставшиеся столбцы в качестве кадра данных вместо ряда в качестве первого параметра в str.cat(). Я исправлю ответ – LeoRochael 23 July 2018 в 21:42
  • 5
    Спасибо за это – ZakS 24 July 2018 в 08:34
dataframe["period"] = dataframe["Year"].map(str) + dataframe["quarter"]
211
ответ дан silvado 17 August 2018 в 12:52
поделиться
  • 1
    Можно ли добавить несколько столбцов вместе без ввода всех столбцов? Скажем, например, add(dataframe.iloc[:, 0:10])? – Heisenberg 9 May 2015 в 19:15
  • 2
    @Heisenberg Это должно быть возможно с встроенным Python sum. – silvado 11 May 2015 в 11:06
  • 3
    @silvado не могли бы вы привести пример добавления нескольких столбцов? спасибо – c1c1c1 25 October 2016 в 16:45
  • 4
    Будьте осторожны, вам нужно применить карту (str) ко всем столбцам, которые не являются строками в первую очередь. если бы четверть была номером, который вы сделали бы dataframe["period"] = dataframe["Year"].map(str) + dataframe["quarter"].map(str), карта просто применяет преобразование строк ко всем записям. – Ozgur Ozturk 1 February 2017 в 22:17
  • 5
    Это решение может создавать проблемы, если у вас есть значения nan, будьте осторожны – Javier 27 December 2017 в 18:14

Хотя ответ @silvado хорош, если вы меняете df.map(str) на df.astype(str), это будет быстрее:

import pandas as pd
df = pd.DataFrame({'Year': ['2014', '2015'], 'quarter': ['q1', 'q2']})

In [131]: %timeit df["Year"].map(str)
10000 loops, best of 3: 132 us per loop

In [132]: %timeit df["Year"].astype(str)
10000 loops, best of 3: 82.2 us per loop
10
ответ дан Anton Protopopov 17 August 2018 в 12:52
поделиться

Использование zip может быть еще более быстрым:

dataframe["period"] = ([''.join(i) for i in 
                        zip(dataframe["Year"].map(str),dataframe["quarter"])])

В наборе данных ниже zip() был наиболее удачным из всех: https://stackoverflow.com/a/50316945/ 7386332

import pandas as pd

data = '''\
ID,Host,Protocol,Port
1,10.0.0.10,tcp,445
1,10.0.0.10,tcp,445
1,10.0.0.10,tcp,445
1,10.0.0.10,tcp,445
1,10.0.0.10,tcp,445
1,10.0.0.10,tcp,445
1,10.0.0.10,tcp,445
1,10.0.0.10,tcp,49707
1,10.0.0.10,tcp,49672
1,10.0.0.10,tcp,49670'''

df = pd.read_csv(pd.compat.StringIO(data)) # Recreates a sample dataframe

df = pd.concat([df]*10000)

%timeit df['Host'] + "/" + df['Protocol'] + "/" + df['Port'].map(str)
%timeit ['/'.join(i) for i in zip(df['Host'],df['Protocol'],df['Port'].map(str))]
%timeit ['/'.join(i) for i in df[['Host','Protocol','Port']].astype(str).values]

10 loops, best of 3: 39.7 ms per loop  
10 loops, best of 3: 35.9 ms per loop  
10 loops, best of 3: 162 ms per loop
3
ответ дан Anton vBR 17 August 2018 в 12:52
поделиться
  • 1
    интересно, что у нас его не было раньше ;-) +1 – MaxU 5 June 2018 в 13:21

Использование лямбда-функции на этот раз с помощью string.format ().

import pandas as pd
df = pd.DataFrame({'Year': ['2014', '2015'], 'Quarter': ['q1', 'q2']})
print df
df['YearQuarter'] = df[['Year','Quarter']].apply(lambda x : '{}{}'.format(x[0],x[1]), axis=1)
print df

  Quarter  Year
0      q1  2014
1      q2  2015
  Quarter  Year YearQuarter
0      q1  2014      2014q1
1      q2  2015      2015q2

Это позволяет вам работать с ненулевыми и переформатировать значения по мере необходимости.

import pandas as pd
df = pd.DataFrame({'Year': ['2014', '2015'], 'Quarter': [1, 2]})
print df.dtypes
print df

df['YearQuarter'] = df[['Year','Quarter']].apply(lambda x : '{}q{}'.format(x[0],x[1]), axis=1)
print df

Quarter     int64
Year       object
dtype: object
   Quarter  Year
0        1  2014
1        2  2015
   Quarter  Year YearQuarter
0        1  2014      2014q1
1        2  2015      2015q2
22
ответ дан Bill Gale 17 August 2018 в 12:52
поделиться
def madd(x):
    """Performs element-wise string concatenation with multiple input arrays.

    Args:
        x: iterable of np.array.

    Returns: np.array.
    """
    for i, arr in enumerate(x):
        if type(arr.item(0)) is not str:
            x[i] = x[i].astype(str)
    return reduce(np.core.defchararray.add, x)

Например:

data = list(zip([2000]*4, ['q1', 'q2', 'q3', 'q4']))
df = pd.DataFrame(data=data, columns=['Year', 'quarter'])
df['period'] = madd([df[col].values for col in ['Year', 'quarter']])

df

    Year    quarter period
0   2000    q1  2000q1
1   2000    q2  2000q2
2   2000    q3  2000q3
3   2000    q4  2000q4
0
ответ дан BMW 17 August 2018 в 12:52
поделиться

более эффективен

def concat_df_str1(df):
    """ run time: 1.3416s """
    return pd.Series([''.join(row.astype(str)) for row in df.values], index=df.index)

, и вот время:

import numpy as np
import pandas as pd

from time import time


def concat_df_str1(df):
    """ run time: 1.3416s """
    return pd.Series([''.join(row.astype(str)) for row in df.values], index=df.index)


def concat_df_str2(df):
    """ run time: 5.2758s """
    return df.astype(str).sum(axis=1)


def concat_df_str3(df):
    """ run time: 5.0076s """
    df = df.astype(str)
    return df[0] + df[1] + df[2] + df[3] + df[4] + \
           df[5] + df[6] + df[7] + df[8] + df[9]


def concat_df_str4(df):
    """ run time: 7.8624s """
    return df.astype(str).apply(lambda x: ''.join(x), axis=1)


def main():
    df = pd.DataFrame(np.zeros(1000000).reshape(100000, 10))
    df = df.astype(int)

    time1 = time()
    df_en = concat_df_str4(df)
    print('run time: %.4fs' % (time() - time1))
    print(df_en.head(10))


if __name__ == '__main__':
    main()

final, когда используется sum (concat_df_str2), результат не просто concat, он преобразуется в целое число.

8
ответ дан Colin Wang 17 August 2018 в 12:52
поделиться
  • 1
    +1 Хорошее решение, это также позволяет нам указывать столбцы: например. df.values[:, 0:3] или df.values[:, [0,2]]. – Snow bunting 9 February 2018 в 10:51

Используйте .combine_first.

df['Period'] = df['Year'].combine_first(df['Quarter'])
1
ответ дан Keiku 17 August 2018 в 12:52
поделиться

мой ответ немного запоздал, но я думаю, что позже лучше, чем никогда. Предположим, что ваш dataframe - df со столбцами Year и Quarter.

import pandas as pd
df = pd.DataFrame({'Quarter':'q1 q2 q3 q4'.split(), 'Year':'2000'})

Предположим, что мы хотим видеть фрейм данных;

df
>>>  Quarter    Year
   0    q1      2000
   1    q2      2000
   2    q3      2000
   3    q4      2000

Наконец , соедините Year и Quarter следующим образом.

df['Period'] = df['Year'] + ' ' + df['Quarter']

Теперь вы можете print df видеть результирующий фрейм.

df
>>>  Quarter    Year    Period
    0   q1      2000    2000 q1
    1   q2      2000    2000 q2
    2   q3      2000    2000 q3
    3   q4      2000    2000 q4

Если вам не нужно пространство между годом и кварталом, просто удалите его, выполнив:

df['Period'] = df['Year'] + df['Quarter']

Надеюсь, это вам поможет.

2
ответ дан Nde Samuel Mbah 17 August 2018 в 12:52
поделиться
  • 1
    Указаны как строки df['Period'] = df['Year'].map(str) + df['Quarter'].map(str) – Stuber 7 August 2018 в 18:58

Вот реализация, которую я нахожу очень универсальной:

In [1]: import pandas as pd 

In [2]: df = pd.DataFrame([[0, 'the', 'quick', 'brown'],
   ...:                    [1, 'fox', 'jumps', 'over'], 
   ...:                    [2, 'the', 'lazy', 'dog']],
   ...:                   columns=['c0', 'c1', 'c2', 'c3'])

In [3]: def str_join(df, sep, *cols):
   ...:     from functools import reduce
   ...:     return reduce(lambda x, y: x.astype(str).str.cat(y.astype(str), sep=sep), 
   ...:                   [df[col] for col in cols])
   ...: 

In [4]: df['cat'] = str_join(df, '-', 'c0', 'c1', 'c2', 'c3')

In [5]: df
Out[5]: 
   c0   c1     c2     c3                cat
0   0  the  quick  brown  0-the-quick-brown
1   1  fox  jumps   over   1-fox-jumps-over
2   2  the   lazy    dog     2-the-lazy-dog
10
ответ дан Pedro M Duarte 17 August 2018 в 12:52
поделиться
  • 1
    FYI: Этот метод отлично работает с Python 3, но дает мне проблемы с Python 2. – Alex P. Miller 31 July 2017 в 19:40

Как уже упоминалось ранее, вы должны преобразовать каждый столбец в строку и затем использовать оператор плюс для объединения двух столбцов строки. Вы можете получить большое улучшение производительности, используя NumPy.

%timeit df['Year'].values.astype(str) + df.quarter
71.1 ms ± 3.76 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit df['Year'].astype(str) + df['quarter']
565 ms ± 22.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
2
ответ дан Ted Petrou 17 August 2018 в 12:52
поделиться

Когда ваши данные вставлены в кадр данных, эта команда должна решить вашу проблему:

df['period'] = df[['Year', 'quarter']].apply(lambda x: ' '.join(x.astype(str)), axis=1)
11
ответ дан VickyK 17 August 2018 в 12:52
поделиться
0
ответ дан user8383881 29 October 2018 в 15:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: