pandas / pythonのデータフレームで2列のテキストを組み合わせる


487

パンダを使用してPythonに20 x 4000のデータフレームがあります。これらの列のうち2つはYearおよびと名付けられていquarterます。私はと呼ばれる変数を作成したいのですがperiod可能ということYear = 2000quarter= q2にします2000q2

誰かがそれを手伝ってくれる?

回答:


530

両方の列が文字列の場合、それらを直接連結できます。

df["period"] = df["Year"] + df["quarter"]

列の1つ(または両方)が文字列型でない場合は、最初に(それらを)変換する必要があります。

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

これを行うときはNaNに注意してください!


複数の文字列列を結合する必要がある場合は、次を使用できますagg

df['period'] = df[['Year', 'quarter', ...]].agg('-'.join, axis=1)

「-」はセパレータです。


13
すべての列を入力せずに複数の列を一緒に追加することは可能ですか?add(dataframe.iloc[:, 0:10])例を挙げましょうか?
ハイゼンベルク、2015年

5
@HeisenbergこれはPython組み込みで可能になるはずsumです。
silvado

6
@silvado複数の列を追加する例を作っていただけませんか?ありがとう
c1c1c1

6
注意してください、最初に文字列ではないすべての列にmap(str)を適用する必要があります。四半期が数値の場合、 dataframe["period"] = dataframe["Year"].map(str) + dataframe["quarter"].map(str)マップはすべてのエントリに文字列変換を適用するだけです。
Ozgur Ozturk 2017

13
あなたはNaN値を持つIYこの解決策は、問題を作成することができ、電子慎重

269
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()メソッドの詳細は、こちらで確認できます


20
lambda x: ''.join(x)ただ''.join、違う?
DSM

6
@OzgurOzturk:ポイントは、構造のラムダ部分lambda x: ''.join(x)は何もしないということです。lambda x: sum(x)単にの代わりにを使用するようなものsumです。
DSM

4
''.joinつまり、を使用した場合と同じ結果が確認されましたdf['period'] = df[['Year', 'quarter']].apply(''.join, axis=1)
マックスジェニス2017年

1
@Archie joinはイテラブルstr内のインスタンスのみを取ります。a mapを使用してすべてをに変換してstrからを使用しますjoin
John Strood 2018年

16
'-'。join(x.map(str))
Manjul

257

小さなデータセット(<150rows)

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

または少し遅くなりますがよりコンパクトです:

df.Year.str.cat(df.quarter)

より大きなデータセット(> 150行)

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

更新:タイミンググラフパンダ0.23.4

ここに画像の説明を入力してください

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)

更新: 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

@ anton-vbrによる投稿への回答


あなたのタイミングで261と264の違いは何ですか?
アントンプロトポポフ2016年

@AntonProtopopovはどこからともなく100ms :)
Dennis Golomazov

@AntonProtopopov、それは2つのタイミングの混合だと思います-1つはCPU / GPU最適化を使用し、もう1つは使用しませんでした。私は私の答えを更新し、そこに両方の​​タイミングセットを配置しました...
MaxU

この.sum()の使用は、すべての列が整数のように見える場合(つまり、整数の文字列形式である場合)は失敗します。代わりに、パンダはそれらを合計する前に数値に変換し直しているようです!
CPBL

@CPBL、このアプローチを試してください:df.T.apply(lambda x: x.str.cat(sep=''))
MaxU

157

アクセサーのメソッド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()、最初の列(Series)で呼び出されるパラメーターとして、最初の列を除くすべてを含むシリーズまたはデータフレームのリストを渡すだけです。

>>> 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

パンダのデータフレーム/シリーズにnull値がある場合は、パラメーターna_repを含めてNaN値を文字列に置き換える必要があります。それ以外の場合、結合された列はデフォルトでNaNになります。


12
これは、lambdaまたはよりもはるかに優れているようです(おそらくより効率的でもあります)map。また、それは最もきれいに読みます。
dwanderson 2016年

1
@ZakS、最初のパラメーターとしてシリーズではなくデータフレームとして残りの列を渡すことによってstr.cat()。私は答えを修正します
LeoRochael 18/07/23

どのバージョンのパンダを使用していますか?ValueErrorが表示されます:sepキーワードを指定するつもりでしたか?パンダ-0.23.4で。ありがとう!
Qinqing Liu

@QinqingLiu、私はこれらをpandas-0.23.4で再テストしましたが、動作しているようです。sepあなたが連結された文字列の部分を分離する場合、パラメータにのみ必要です。エラーが発生した場合は、失敗した例を示してください。
LeoRochael

31

今回はstring.format()でのlamba関数の使用。

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

1
より速く:.apply( ''。join(x)、axis = 1)
Ghanem

19

あなたの質問に対する簡単な答え。

    year    quarter
0   2000    q1
1   2000    q2

> df['year_quarter'] = df['year'] + '' + df['quarter']

> print(df['year_quarter'])
  2000q1
  2000q2

3
Year文字列でない場合は失敗します
geher

4
使用df['Year'].astype(str) + '' + df['quarter'].astype(str)
Yedhrab

2
このソリューションのポイントは、トップの回答と同じであるため、正確には何ですか?
AMC

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

12

あなたdataframedfYearとを持っているとしましょう 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

最後に、YearQuarterを次のように連結します。

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']

3
文字列として指定df['Period'] = df['Year'].map(str) + df['Quarter'].map(str)
Stuber 2018

またはのTypeError: Series cannot perform the operation +いずれかを実行すると取得されます。df2['filename'] = df2['job_number'] + '.' + df2['task_number']df2['filename'] = df2['job_number'].map(str) + '.' + df2['task_number'].map(str)
Karl Baker

しかし、df2['filename'] = df2['job_number'].astype(str) + '.' + df2['task_number'].astype(str)うまくいきました。
Karl Baker

@KarlBaker、私はあなたの入力に文字列がなかったと思います。しかし、あなたがそれを理解したことをうれしく思います。dataframe上記で作成した例を見ると、すべての列がstrings であることがわかります。
Samuel Nde

このソリューションのポイントは、トップの回答と同じであるため、正確には何ですか?
AMC

10

ここに私が非常に用途が広いと思う実装があります:

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

FYI:このメソッドは、Python 3で素晴らしい作品が、Pythonの2に私に迷惑を与える
アレックスP. Millerの

10

データがデータフレームに挿入されると、このコマンドはあなたの問題を解決するはずです:

df['period'] = df[['Year', 'quarter']].apply(lambda x: ' '.join(x.astype(str)), axis=1)

この回答は、以前の人気のある回答と同じです。
AMC

9

より効率的です

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()

最後に、sum(concat_df_str2)を使用すると、結果は単に連結ではなく、整数に変換されます。


+1きちんとしたソリューション。これにより、列を指定することもできます。例:df.values[:, 0:3]またはdf.values[:, [0,2]]
雪のホオジロ2018

9

複数の列に一般化する理由:

columns = ['whatever', 'columns', 'you', 'choose']
df['period'] = df[columns].astype(str).sum(axis=1)

見た目はかっこいいですが、「-」のように文字列の間に区切り文字を追加したい場合はどうすればよいですか?
Odisseo

この回答を参照@Odisseo stackoverflow.com/questions/19377969/...
geher

6

使用zipするとさらに速くなる可能性があります:

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

グラフ:

ここに画像の説明を入力してください

import pandas as pd
import numpy as np
import timeit
import matplotlib.pyplot as plt
from collections import defaultdict

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

myfuncs = {
"df['Year'].astype(str) + df['quarter']":
    lambda: df['Year'].astype(str) + df['quarter'],
"df['Year'].map(str) + df['quarter']":
    lambda: df['Year'].map(str) + df['quarter'],
"df.Year.str.cat(df.quarter)":
    lambda: df.Year.str.cat(df.quarter),
"df.loc[:, ['Year','quarter']].astype(str).sum(axis=1)":
    lambda: df.loc[:, ['Year','quarter']].astype(str).sum(axis=1),
"df[['Year','quarter']].astype(str).sum(axis=1)":
    lambda: df[['Year','quarter']].astype(str).sum(axis=1),
    "df[['Year','quarter']].apply(lambda x : '{}{}'.format(x[0],x[1]), axis=1)":
    lambda: df[['Year','quarter']].apply(lambda x : '{}{}'.format(x[0],x[1]), axis=1),
    "[''.join(i) for i in zip(dataframe['Year'].map(str),dataframe['quarter'])]":
    lambda: [''.join(i) for i in zip(df["Year"].map(str),df["quarter"])]
}

d = defaultdict(dict)
step = 10
cont = True
while cont:
    lendf = len(df); print(lendf)
    for k,v in myfuncs.items():
        iters = 1
        t = 0
        while t < 0.2:
            ts = timeit.repeat(v, number=iters, repeat=3)
            t = min(ts)
            iters *= 10
        d[k][lendf] = t/iters
        if t > 2: cont = False
    df = pd.concat([df]*step)

pd.DataFrame(d).plot().legend(loc='upper center', bbox_to_anchor=(0.5, -0.15))
plt.yscale('log'); plt.xscale('log'); plt.ylabel('seconds'); plt.xlabel('df rows')
plt.show()

6

最も簡単なソリューション:

一般的なソリューション

df['combined_col'] = df[['col1', 'col2']].astype(str).apply('-'.join, axis=1)

質問固有の解決策

df['quarter_year'] = df[['quarter', 'year']].astype(str).apply(''.join, axis=1)

.joinの前に引用符内で優先する区切り文字を指定します


これは、より古く、より一般的な回答と同じではありませんか?
AMC

5

このソリューションでは、中間ステップを使用して、DataFrameの2つの列を、値のリスト含む1つの列に圧縮します。これは文字列だけでなく、あらゆる種類のcolumn-dtypeで機能します

import pandas as pd
df = pd.DataFrame({'Year': ['2014', '2015'], 'quarter': ['q1', 'q2']})
df['list']=df[['Year','quarter']].values.tolist()
df['period']=df['list'].apply(''.join)
print(df)

結果:

   Year quarter        list  period
0  2014      q1  [2014, q1]  2014q1
1  2015      q2  [2015, q2]  2015q2

他のdtypeが機能しないようです。TypeErrorが発生しました:シーケンスアイテム1:予期されるstrインスタンス、floatが見つかりました
Prometheus

最初にキャストを文字列に適用します。結合操作は文字列に対してのみ機能します
Markus Dutschke、

この解決策は、dtypeが異なる2つの列を組み合わせるには機能しません。そのような場合の正しい解決策については、私の回答を参照してください。
グッドウィル

2

前述のとおり、各列を文字列に変換してから、プラス演算子を使用して2つの文字列列を結合する必要があります。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)

numpyifiedバージョンを使用したいのですが、エラーが発生します:入力df2['filename'] = df2['job_number'].values.astype(str) + '.' + df2['task_number'].values.astype(str)-> 出力TypeError: ufunc 'add' did not contain a loop with signature matching types dtype('<U21') dtype('<U21') dtype('<U21')。job_numberとtask_numberはどちらもintです。
Karl Baker

これは、2つの複雑な配列を組み合わせるためです。numpy配列をpandasシリーズと組み合わせると機能します。asdf['Year'].values.astype(str) + df.quarter
AbdulRehmanLiaqat

2

パンダで列を組み合わせる最良の方法は、両方の列を整数に変換してからstrに変換することです。

df[['Year', 'quarter']] = df[['Year', 'quarter']].astype(int).astype(str)
df['Period']= df['Year'] + 'q' + df['quarter']

両方の列を整数に変換するなぜ最初にintに変換するのですか?その奇妙さを取り除くと、この解決策は現在のトップの回答と同じになります。
AMC

2

列の値の間にセパレータを使用して、intとstrの値を持つ2つの列を新しい列に連結/結合する上記のソリューションの私の要約は次のとおりです。この目的のために3つのソリューションが機能します。

# be cautious about the separator, some symbols may cause "SyntaxError: EOL while scanning string literal".
# e.g. ";;" as separator would raise the SyntaxError

separator = "&&" 

# pd.Series.str.cat() method does not work to concatenate / combine two columns with int value and str value. This would raise "AttributeError: Can only use .cat accessor with a 'category' dtype"

df["period"] = df["Year"].map(str) + separator + df["quarter"]
df["period"] = df[['Year','quarter']].apply(lambda x : '{} && {}'.format(x[0],x[1]), axis=1)
df["period"] = df.apply(lambda x: f'{x["Year"]} && {x["quarter"]}', axis=1)

ありがとうございました!あなたのf-stringソリューションは私が見つけたいと思っていたものでした!!!
leerssej

1

を使用し.combine_firstます。

df['Period'] = df['Year'].combine_first(df['Quarter'])

これは正しくありません。.combine_first結果は、'Year'に格納された値か、'Period'Nullの場合はからの値になります'Quarter'。2つの文字列を連結してに保存することはありません'Period'
Steve G

これは完全に間違っています。
AMC

0
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

DataFrameのassignメソッドを使用できます。

df= (pd.DataFrame({'Year': ['2014', '2015'], 'quarter': ['q1', 'q2']}).
  assign(period=lambda x: x.Year+x.quarter ))

-1
dataframe["period"] = dataframe["Year"].astype(str).add(dataframe["quarter"])

または、値が[2000] [4]のようで、[2000q4]を作成したい場合

dataframe["period"] = dataframe["Year"].astype(str).add('q').add(dataframe["quarter"]).astype(str)

代入する.astype(str).map(str)、あまりにも動作します。


これは基本的にトップの回答と同じです。
AMC
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.