【问题标题】:String-join operation in python numpy or pandas objectspython numpy 或 pandas 对象中的字符串连接操作
【发布时间】:2020-07-14 02:25:32
【问题描述】:

我想将 pandas 数据框或 numupy ndarray 中的字符串类型的列连接到最后一列,如下所示:

        a   b   c                          a   b   c   d
        ----------         --->            ---------------
        a   b   c                          a   b   c   a_b_c             
        d   e   f                          d   e   f   d_e_f
        g   h   i                          g   h   i   g_h_i

我能想到两个有代表性的选项:

# Compose data
a = ['a','b','c']
b = ['d','e','f']
c = ['g','h','i']

pdf = pd.DataFrame([a,b,c], columns=['a','b','c'])


# One option
%%timeit
pdf.loc[:,'d'] = [i for i in map(lambda x: '_'.join([x.a, x.b, x.c]), pdf.itertuples())]
>>>1.08 ms ± 4.11 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

# Another option
%%timeit
tmp=[]
for i in pdf.itertuples():
    tmp.append('_'.join([i.a, i.b, i.c]))

pdf.loc[:,'d'] = tmp
>>>1.08 ms ± 5.54 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
 

我知道数据可能太少,看不出这些方法之间有什么区别,但我的问题是:我可以调用 numpy 或 pandas 中内置的更智能的方法吗? 另外,我想到的这两种方法有什么问题吗?

谢谢!

【问题讨论】:

  • 根据我的经验和知识...... pandas 在下面使用 numpy,因此,pandas 增加了操作的开销。使用直接 numpy 与 pandas 相比,几乎所有操作都更快。

标签: python pandas numpy


【解决方案1】:

你可以试试下面这两个,不必使用循环:

df['combined'] = df['a'] + '_' + df['b'] + '_' + df['c']

或:

df['combined'] = df[['a', 'b', 'c']].agg('_'.join, axis=1)

   a  b  c combined
0  a  b  c    a_b_c
1  d  e  f    d_e_f
2  g  h  i    g_h_i

【讨论】:

  • 第一个看起来不错,但后一个(agg) 的表现非常差。
  • 显式转换为 numpy 数组(即pdf['a'].to_numpy() + '_' + pdf['b'].to_numpy() + '_' + pdf['c'].to_numpy())将产生更好的时间性能(在我的本地机器上它快 20 倍)
【解决方案2】:

我想抛出另一个选项:

pdf['a'].str.cat([pdf['b'], pdf['c']], sep='_')

输出:

0    a_b_c
1    d_e_f
2    g_h_i
Name: a, dtype: object

时间

# Compose data
a = ['a','b','c']
b = ['d','e','f']
c = ['g','h','i']

pdf = pd.DataFrame([a,b,c], columns=['a','b','c'])



def met_add(d):
    return df['a'] + '_' + df['b'] + '_' + df['c']

def met_agg_axis1(d):
    return  df[['a', 'b', 'c']].agg('_'.join, axis=1)

def met_str_cat(d):
    return pdf['a'].str.cat([pdf['b'], pdf['c']], sep='_')

def met_map_join(d):
    return pd.Series( [i for i in map(lambda x: '_'.join([x.a, x.b, x.c]), pdf.itertuples())])

def met_iter_join(d):
    tmp=[]
    for i in pdf.itertuples():
        tmp.append('_'.join([i.a, i.b, i.c]))
    return pd.Series(tmp)    

def met_numpy_add(d):
    return pd.Series(pdf['a'].to_numpy() + '_' + pdf['b'].to_numpy() + '_' + pdf['c'].to_numpy())

res = pd.DataFrame(
    index=[10, 30, 100, 300,1000, 3000, 10000, 30000, 100000, 300000],
    columns='met_add met_agg_axis1 met_str_cat met_map_join met_iter_join met_numpy_add'.split(),
    dtype=float
)

for i in res.index:
    d = pd.concat([pdf]*i).add_prefix('col')
    for j in res.columns:
        print(d.shape)
        stmt = '{}(d)'.format(j)
        setp = 'from __main__ import d, {}'.format(j)
        res.at[i, j] = timeit(stmt, setp, number=100)

res.plot(loglog=True, figsize=(10,8));

图表输出:

【讨论】:

    【解决方案3】:

    鉴于您提供的数据和您正在使用的少量列,您可能会发现简单地使用 + 运算符来连接您希望加入的列会更容易(但不可扩展):

    pdf['d'] = pdf['a'] + '_' + pdf['b'] + '_' + pdf['c']
    

    如果您有 200 列,它是不可扩展的,但它肯定比您建议的其他两种方法更快。在 30000 行数据框中使用它,我得到以下时间结果:

    a = ['a','b','c']
    b = ['d','e','f']
    c = ['g','h','i']
    
    pdf = pd.DataFrame([a,b,c]*10000, columns=['a','b','c'])
    

    以下是时间结果:

    Method 1:  0.041734933853149414
    Method 2:  0.04217410087585449
    Method 3:  0.011157751083374023
    

    其中方法1和2是建议的方法,第三种是上面的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-25
      • 1970-01-01
      • 2020-09-07
      • 2011-05-09
      • 2015-05-31
      • 1970-01-01
      • 2021-02-04
      相关资源
      最近更新 更多