如何在Pandas中从两列创建元组列

234

我有一个Pandas DataFrame,想把'lat'和'long'列合并成一个元组。

<class 'pandas.core.frame.DataFrame'>
Int64Index: 205482 entries, 0 to 209018
Data columns:
Month           205482  non-null values
Reported by     205482  non-null values
Falls within    205482  non-null values
Easting         205482  non-null values
Northing        205482  non-null values
Location        205482  non-null values
Crime type      205482  non-null values
long            205482  non-null values
lat             205482  non-null values
dtypes: float64(4), object(5)

我尝试使用的代码是:

def merge_two_cols(series): 
    return (series['lat'], series['long'])

sample['lat_long'] = sample.apply(merge_two_cols, axis=1)

然而,这导致了以下错误:

---------------------------------------------------------------------------
 AssertionError                            Traceback (most recent call last)
<ipython-input-261-e752e52a96e6> in <module>()
      2     return (series['lat'], series['long'])
      3 
----> 4 sample['lat_long'] = sample.apply(merge_two_cols, axis=1)
      5

...

AssertionError: Block shape incompatible with manager 

我该如何解决这个问题?

6个回答

372

熟悉使用 zip,在处理列数据时非常方便。

df['new_col'] = list(zip(df.lat, df.long))

使用applymap反而会更加复杂和慢。像np.dstack这样的方法比zip快两倍,但不会给出元组。


7
在Python3中,你需要使用 list。下面的代码应该可以起作用:df['new_col'] = list(zip(df.lat, df.long)) - paulwasit
@paulwasit 哦,没错,我和 Python 3 的惰性行为之间有一种爱恨交加的关系。谢谢。 - Dale
15
这个方法list(zip(df.lat, df.long))在124毫秒内比df[['lat', 'long']].apply(tuple, axis=1)更有效,后者需要14.2秒才能完成对于900k行数据的处理。两者效率相差超过100倍。 - Pengju Zhao
1
我正在尝试将此代码用于更长的列列表 df['new_col'] = list(zip(df[cols_to_keep])),但是一直出现错误:值的长度与索引的长度不匹配。有什么建议吗? - seeiespi
5
@PeterHansen的回答对我有帮助,但我认为可能缺少了一个*以先解包列表-即: df['new_col'] = list(zip(*[df[c] for c in cols_to_keep]) - jedge
显示剩余3条评论

103
In [10]: df
Out[10]:
          A         B       lat      long
0  1.428987  0.614405  0.484370 -0.628298
1 -0.485747  0.275096  0.497116  1.047605
2  0.822527  0.340689  2.120676 -2.436831
3  0.384719 -0.042070  1.426703 -0.634355
4 -0.937442  2.520756 -1.662615 -1.377490
5 -0.154816  0.617671 -0.090484 -0.191906
6 -0.705177 -1.086138 -0.629708  1.332853
7  0.637496 -0.643773 -0.492668 -0.777344
8  1.109497 -0.610165  0.260325  2.533383
9 -1.224584  0.117668  1.304369 -0.152561

In [11]: df['lat_long'] = df[['lat', 'long']].apply(tuple, axis=1)

In [12]: df
Out[12]:
          A         B       lat      long                             lat_long
0  1.428987  0.614405  0.484370 -0.628298      (0.484370195967, -0.6282975278)
1 -0.485747  0.275096  0.497116  1.047605      (0.497115615839, 1.04760475074)
2  0.822527  0.340689  2.120676 -2.436831      (2.12067574274, -2.43683074367)
3  0.384719 -0.042070  1.426703 -0.634355      (1.42670326172, -0.63435462504)
4 -0.937442  2.520756 -1.662615 -1.377490     (-1.66261469102, -1.37749004179)
5 -0.154816  0.617671 -0.090484 -0.191906  (-0.0904840623396, -0.191905582481)
6 -0.705177 -1.086138 -0.629708  1.332853     (-0.629707821728, 1.33285348929)
7  0.637496 -0.643773 -0.492668 -0.777344   (-0.492667604075, -0.777344111021)
8  1.109497 -0.610165  0.260325  2.533383        (0.26032456699, 2.5333825651)
9 -1.224584  0.117668  1.304369 -0.152561     (1.30436900612, -0.152560909725)

太棒了。谢谢你。显然需要理解Lambda函数。 - elksie5000
这段代码在你的数据上运行了吗?如果是的话,你可以分享一下你使用的 pandas 版本和数据吗?我想知道为什么你的代码没有生效,它应该是有效的。 - Wouter Overmeire
版本号为0.10.1_20130131。请原谅我的无知,上传数据的最佳方式是什么?(我还是一个相对新手)。 - elksie5000
我有一个代码 df[["year", "month", "day"]].apply(tuple, axis=1),其中的"year"、"month"和"day"只是整数,但它无法执行任何操作。编辑:这仅适用于浮点数,真是一门让人头疼的语言。 - imrek
2
我已经点赞了这个回答,因为我需要压缩10列并且不想给数据框命名10次,只想给出列名。 - rishi jain
显示剩余3条评论

30

Pandas有 itertuples 方法可以精准实现此功能:

list(df[['lat', 'long']].itertuples(index=False, name=None))

10

建议您尝试使用 pd.to_records(index=False)

import pandas as pd
df = pd.DataFrame({'language': ['en', 'ar', 'es'], 'greeting': ['Hi', 'اهلا', 'Hola']})
df

   language  greeting
0       en    Hi
1       ar    اهلا
2       es   Hola

df['list_of_tuples'] = list(df[['language', 'greeting']].to_records(index=False))
df['list_of_tuples']

0    [en, Hi]
1    [ar, اهلا]
2    [es, Hola]

尽情享受吧!


7

我想添加 df.values.tolist()。(只要你不介意获取列表而不是元组的列)

import pandas as pd
import numpy as np

size = int(1e+07)
df = pd.DataFrame({'a': np.random.rand(size), 'b': np.random.rand(size)}) 

%timeit df.values.tolist()
1.47 s ± 38.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit list(zip(df.a,df.b))
1.92 s ± 131 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

1
当你有超过这两列时:%timeit df[['a', 'b']].values.tolist()。它仍然要快得多。 - ChaimG
创建它的速度更快,但是在元组形式下对该列的任何操作都会更快。例如,尝试在列表列和元组列上调用.value_counts() - ThatNewGuy
现在推荐使用df.to_numpy()而不是df.values(参见这里),所以最好使用df.to_numpy().tolist() - user343233

1
假设你有两列"A"和"B":
import pandas as pd
df = pd.DataFrame({'A': ['one', 'two', 'three'], 'B': [1, 2, 3]})

print(df)

    A   B
0   x   1
1   y   2
2   z   3

现在您想要将 A 和 B 列合并在一起,可以这样做:

print(df[['A', 'B']].apply(list, axis=1))

0      [one, 1]
1      [two, 2]
2    [three, 3]
dtype: object

或者如果你想要嵌套列表的话:

print(df[['A', 'B']].apply(list, axis=1).tolist())

#[['one', 1], ['two', 2], ['three', 3]]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接