在pandas/python中的数据框中组合两列文本

use*_*103 395 python numpy dataframe pandas

我在使用pandas的python中有一个20 x 4000的数据帧.其中两列名为Year和quarter.我想创建一个名为period的变量,将Year = 2000和quarter = q2变为2000q2

任何人都可以帮忙吗?

sil*_*ado 378

dataframe["period"] = dataframe["Year"].map(str) + dataframe["quarter"]
Run Code Online (Sandbox Code Playgroud)

  • 是否可以在不键入所有列的情况下将多个列添加到一起?让我们说`add(dataframe.iloc [:,0:10])`例如? (12认同)
  • 这个解决方案可能会产生问题,因为你有纳米价值,小心 (8认同)
  • @silvado你可以举个例子来添加多个列吗?谢谢 (6认同)
  • @Heisenberg应该可以使用Python内置的``sum``. (5认同)
  • 注意,您需要将map(str)应用于首先不是字符串的所有列.如果quarter是数字,你会做`dataframe ["period"] = dataframe ["Year"].map(str)+ dataframe ["quarter"].map(str)`map只是将字符串转换应用于所有条目. (5认同)
  • 还便于轻松添加分隔符。例如分隔符 '__': ```dataframe["period"] = dataframe["Year"].map(str) + '__' + dataframe["quarter"]``` (4认同)
  • 使用“.apply(lambda x: '_'.join(x), axis=1)”代替“.agg...”。这比 .agg 版本快 5 倍。 (3认同)
  • 当我使用这个解决方案时,我得到了 `SettingWithCopyWarning` - 我怎样才能在不触发该警告的情况下做到这一点? (2认同)
  • 通常,应将“ astype”用于将pandas.Series转换为其他类型。因此,使用`.astype(str)`代替`.map(str)`。 (2认同)

Rus*_*uss 244

df = pd.DataFrame({'Year': ['2014', '2015'], 'quarter': ['q1', 'q2']})
df['period'] = df[['Year', 'quarter']].apply(lambda x: ''.join(x), axis=1)
Run Code Online (Sandbox Code Playgroud)

产生此数据帧

   Year quarter  period
0  2014      q1  2014q1
1  2015      q2  2015q2
Run Code Online (Sandbox Code Playgroud)

通过替换df[['Year', 'quarter']]数据帧的任何列切片,此方法可以概括为任意数量的字符串列,例如df.iloc[:,0:2].apply(lambda x: ''.join(x), axis=1).

您可以在此处查看有关apply()方法的更多信息

  • `lambda x:''.join(x)`只是'''.join`,不是吗? (19认同)
  • ' - '.加入(x.map(STR)) (15认同)
  • @OzgurOzturk:关键是`lambda x:''.join(x)`构造的lambda部分没有做任何事情; 这就像使用`lambda x:sum(x)`而不仅仅是`sum`. (5认同)
  • 使用`''.join`时确认相同的结果,即:df ['period'] = df [['Year','quarter']]。apply(''。join,axis = 1)`。 (3认同)

Max*_*axU 228

小数据集(<150rows)

[''.join(i) for i in zip(df["Year"].map(str),df["quarter"])]
Run Code Online (Sandbox Code Playgroud)

或略慢但更紧凑:

df.Year.str.cat(df.quarter)
Run Code Online (Sandbox Code Playgroud)

更大的数据集(> 150)

df['Year'].astype(str) + df['quarter']
Run Code Online (Sandbox Code Playgroud)

更新:时序图Pandas 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)
Run Code Online (Sandbox Code Playgroud)

更新:使用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
Run Code Online (Sandbox Code Playgroud)

使用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
Run Code Online (Sandbox Code Playgroud)

由@ anton-vbr回答贡献


Leo*_*ael 145

该方法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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

连接多个列只是传递一个系列列表或一个包含除第一列之外的所有列的数据帧作为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
Run Code Online (Sandbox Code Playgroud)

请注意,如果您的pandas dataframe/series具有空值,则需要包含参数na_rep以使用字符串替换NaN值,否则组合列将默认为NaN.

  • 这似乎比`lambda`或`map`更好(也许更高效); 它也只是读得最干净. (11认同)

Bil*_*ale 30

这次使用lamba函数和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
Run Code Online (Sandbox Code Playgroud)

这允许您根据需要使用非字符串并重新格式化值.

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
Run Code Online (Sandbox Code Playgroud)

  • 更快: .apply(''.join(x), axis=1) (4认同)

Ant*_*pov 12

虽然@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
Run Code Online (Sandbox Code Playgroud)


Sam*_*Nde 12

让我们假设你的 dataframedf柱子YearQuarter.

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

假设我们想要查看数据帧;

df
>>>  Quarter    Year
   0    q1      2000
   1    q2      2000
   2    q3      2000
   3    q4      2000
Run Code Online (Sandbox Code Playgroud)

最后,连接YearQuarter如下.

df['Period'] = df['Year'] + ' ' + df['Quarter']
Run Code Online (Sandbox Code Playgroud)

您现在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
Run Code Online (Sandbox Code Playgroud)

如果您不想要年份和季度之间的空间,只需将其删除;

df['Period'] = df['Year'] + df['Quarter']
Run Code Online (Sandbox Code Playgroud)

  • 指定为字符串`df ['Period'] = df ['Year'].map(str)+ df ['Quarter'].map(str)` (3认同)

小智 11

当您的数据插入到数据框中时,此命令应该可以解决您的问题:

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


Pob*_*huk 11

您可以使用 lambda:

combine_lambda = lambda x: '{}{}'.format(x.Year, x.quarter)
Run Code Online (Sandbox Code Playgroud)

然后将其用于创建新列:

df['period'] = df.apply(combine_lambda, axis = 1)
Run Code Online (Sandbox Code Playgroud)


Ped*_*rte 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
Run Code Online (Sandbox Code Playgroud)


Col*_*ang 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)
Run Code Online (Sandbox Code Playgroud)

这是一个时间测试:

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()
Run Code Online (Sandbox Code Playgroud)

final,当使用sum(concat_df_str2)时,结果不是简单的concat,它将转换为整数.


Mar*_*hke 7

此解决方案使用中间步骤将 DataFrame 的两列压缩为包含列表单个列。这不仅适用于字符串,而且适用于所有类型的列数据类型

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)
Run Code Online (Sandbox Code Playgroud)

结果:

   Year quarter        list  period
0  2014      q1  [2014, q1]  2014q1
1  2015      q2  [2015, q2]  2015q2
Run Code Online (Sandbox Code Playgroud)


geh*_*her 7

归纳为多列,为什么不这样做:

columns = ['whatever', 'columns', 'you', 'choose']
df['period'] = df[columns].astype(str).sum(axis=1)
Run Code Online (Sandbox Code Playgroud)

  • 看起来很酷,但是如果我想在字符串之间添加分隔符(例如“-”)怎么办? (4认同)

Ban*_*nta 7

您问题的简单答案。

    Year    quarter
0   2000    q1
1   2000    q2

> final_string = df['Year'] + '' + df['quarter']

> print(final_string)
  2000q1
  2000q2
Run Code Online (Sandbox Code Playgroud)


Ant*_*vBR 6

使用zip甚至可以更快:

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

图形:

在此处输入图片说明

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()
Run Code Online (Sandbox Code Playgroud)


Goo*_*ill 6

这是我对上述解决方案的总结,这些解决方案使用列值之间的分隔符将具有 int 和 str 值的两列连接/组合到一个新列中。三种解决方案可用于此目的。

# 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)
Run Code Online (Sandbox Code Playgroud)


leo*_*leo 5

我的看法....

listofcols = ['col1','col2','col3']
df['combined_cols'] = ''

for column in listofcols:
    df['combined_cols'] = df['combined_cols'] + ' ' + df[column]
'''
Run Code Online (Sandbox Code Playgroud)

  • 您应该为此代码片段添加解释。仅添加代码答案会鼓励人们使用他们不理解的代码,并且无助于他们学习。 (6认同)