Как сформировать столбец кортежа из двух столбцов в Pandas

126

У меня есть DataFrame Pandas, и я хочу объединить столбцы 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 

Как я могу решить эту проблему?

elksie5000
источник

Ответы:

202

Привыкайте к себе zip. Это удобно при работе с данными столбца.

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

Это проще и быстрее, чем при использовании applyили map. Что-то вроде np.dstackв два раза быстрее zip, но не даст вам кортежей.

Дейл Юнг
источник
3
в python3 вы должны использовать list. Это должно сработать:df['new_col'] = list(zip(df.lat, df.long))
paulwasit
@paulwasit ах да, моя любовь ненавижу отношения с ленивым поведением python 3. Спасибо.
Дейл Юнг,
4
Этот метод list(zip(df.lat, df.long))за 124 мс намного эффективнее, чем df[['lat', 'long']].apply(tuple, axis=1)за 14,2 с для 900 тыс. Строк. Соотношение больше 100.
Pengju Zhao
1
Я пытаюсь использовать это с более длинным списком столбцов, df['new_col'] = list(zip(df[cols_to_keep])) но получаю сообщение об ошибке: Length of values does not match length of indexесть совет?
seeiespi
1
@ Ответ PeterHansen помог мне , но думаю , что это может быть пропущен * распаковывать список первой - то есть df['new_col'] = list(zip(*[df[c] for c in cols_to_keep])
jedge
61
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)
Воутер Овермайр
источник
Это блестяще. Спасибо. Очевидно, мне нужно разобраться с лямбда-функциями.
elksie5000
Это сработало с вашими данными? Если да, можете ли вы поделиться своей версией pandas и данными? Интересно, почему ваш код не работал, так и должно быть.
Wouter Overmeire
Версия - 0.10.1_20130131. Извините за мое незнание, но как лучше всего загрузить раздел данных для вас? (Все еще относительный новичок).
elksie5000
На 0.10.1 воспроизвести не удалось. Лучший способ загрузки? Вы можете либо создать код, который генерирует фрейм, содержащий случайные данные, которые имеют ту же проблему, и поделиться этим кодом, либо выбрать фрейм выше (образец) и передать его через бесплатную службу передачи больших файлов. Как мариновать (в две строки, без ","): импортировать рассол с open ('sample.pickle', 'w') как файл: pickle.dump (sample, file)
Воутер Овермайр
1
Я проголосовал за это, так как мне нужно заархивировать 10 столбцов, и я не хочу 10 раз указывать имя фрейма данных. Просто хочу дать имена столбцам.
риши джайн
13

У Pandas есть itertuplesспособ сделать именно это:

list(df[['lat', 'long']].itertuples(index=False, name=None))
Тед Петру
источник
3

Хочу добавить 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)
user3820991
источник
Если у вас есть больше , чем только эти две колонки: %timeit df[['a', 'b']].values.tolist(). Это все еще намного быстрее.
ChaimG