熊猫:消除循环

时间:2014-01-10 14:24:53

标签: python pandas vectorization dataframe

我有两个Pandas数据帧,即:habitat_familyhabitat_species。我想根据分类habitat_specieslookupMap中的值填充habitat_family

import pandas as pd
import numpy as np
species = ['tiger', 'lion', 'mosquito', 'ladybug', 'locust', 'seal', 'seabass', 'shark', 'dolphin']
families = ['mammal','fish','insect']
lookupMap = {'tiger':'mammal', 'lion':'mammal', 'mosquito':'insect', 'ladybug':'insect', 'locust':'insect',
            'seal':'mammal', 'seabass':'fish', 'shark':'fish', 'dolphin':'mammal' }

habitat_family = pd.DataFrame({'id': range(1,11),
                         'mammal': [101,123,523,562,546,213,562,234,987,901],
                         'fish' :  [625,254,929,827,102,295,174,777,123,763],
                         'insect': [345,928,183,645,113,942,689,539,789,814] 
                         }, index=range(1,11), columns=['id','mammal','fish','insect'])

habitat_species = pd.DataFrame(0.0, index=range(1,11), columns=species)

# My highly inefficient solution:
for id in habitat_family.index: # loop through habitat id's
   for spec in species: # loop through species
       corresp_family = lookupMap[spec]
       habitat_species.loc[id,spec] = habitat_family.loc[id,corresp_family]

上面的嵌套for循环完成了这项工作。但实际上我的数据帧的大小很大,并且使用for循环是不可行的。

是否有更有效的方法可以使用dataframe.apply()或类似功能实现此目的?

编辑:所需的输出habitat_species为:

habitat_species
    tiger  lion  mosquito  ladybug  locust  seal  seabass  shark  dolphin
1     101   101       345      345     345   101      625    625      101
2     123   123       928      928     928   123      254    254      123
3     523   523       183      183     183   523      929    929      523
4     562   562       645      645     645   562      827    827      562
5     546   546       113      113     113   546      102    102      546
6     213   213       942      942     942   213      295    295      213
7     562   562       689      689     689   562      174    174      562
8     234   234       539      539     539   234      777    777      234
9     987   987       789      789     789   987      123    123      987
10    901   901       814      814     814   901      763    763      901

4 个答案:

答案 0 :(得分:3)

根本不需要任何循环。看看:

In [12]: habitat_species = habitat_family[Series(species).replace(lookupMap)]

In [13]: habitat_species.columns = species

In [14]: habitat_species
Out[14]: 
    tiger  lion  mosquito  ladybug  locust  seal  seabass  shark  dolphin
1     101   101       345      345     345   101      625    625      101
2     123   123       928      928     928   123      254    254      123
3     523   523       183      183     183   523      929    929      523
4     562   562       645      645     645   562      827    827      562
5     546   546       113      113     113   546      102    102      546
6     213   213       942      942     942   213      295    295      213
7     562   562       689      689     689   562      174    174      562
8     234   234       539      539     539   234      777    777      234
9     987   987       789      789     789   987      123    123      987
10    901   901       814      814     814   901      763    763      901

[10 rows x 9 columns]

答案 1 :(得分:2)

首先,写得非常精彩。感谢。

我建议为每个系列制作一个DataFrame,并在最后连接: 您需要撤销lookupMap

In [80]: d = {'mammal': ['dolphin', 'lion', 'seal', 'tiger'], 'insect': ['ladybug', 'locust', 'mosquito'], 'fish': 
['seabass', 'shark']}

以此为例:

In [83]: k, v = 'mammal', d['mammal']

In [86]: pd.DataFrame([habitat_family[k] for _ in v], index=v).T
Out[86]: 
    dolphin  lion  seal  tiger
1       101   101   101    101
2       123   123   123    123
3       523   523   523    523
4       562   562   562    562
5       546   546   546    546
6       213   213   213    213
7       562   562   562    562
8       234   234   234    234
9       987   987   987    987
10      901   901   901    901

[10 rows x 4 columns]

现在为每个家庭做这件事:

In [88]: for k, v in d.iteritems():
   ....:     results.append(pd.DataFrame([habitat_family[k] for _ in v], index=v).T)

concat:

In [89]: habitat_species = pd.concat(results, axis=1)

In [90]: habi
habitat_family   habitat_species  

In [90]: habitat_species
Out[90]: 
    dolphin  lion  seal  tiger  ladybug  locust  mosquito  seabass  shark
1       101   101   101    101      345     345       345      625    625
2       123   123   123    123      928     928       928      254    254
3       523   523   523    523      183     183       183      929    929
4       562   562   562    562      645     645       645      827    827
5       546   546   546    546      113     113       113      102    102
6       213   213   213    213      942     942       942      295    295
7       562   562   562    562      689     689       689      174    174
8       234   234   234    234      539     539       539      777    777
9       987   987   987    987      789     789       789      123    123
10      901   901   901    901      814     814       814      763    763

[10 rows x 9 columns]

如果您想要具有(家庭,种类)对的列的分层索引,您可以考虑将这些系列作为key参数传递给concat

一些分析,因为你说性能很重要:

# Mine
In [97]: %%timeit
   ....: for k, v in d.iteritems():
   ....:     results.append(pd.DataFrame([habitat_family[k] for _ in v], index=v).T)
   ....: habitat_species = pd.concat(results, axis=1)
   ....: 
1 loops, best of 3: 296 ms per loop

# Your's
In [98]: %%timeit
   ....: for id in habitat_family.index: # loop through habitat id's
   ....:    for spec in species: # loop through species
   ....:        corresp_family = lookupMap[spec]
   ....:        habitat_species.loc[id,spec] = habitat_family.loc[id,corresp_family]
10 loops, best of 3: 21.5 ms per loop

# Dan's
In [102]: %%timeit
   .....: habitat_species = habitat_family[Series(species).replace(lookupMap)]
   .....: habitat_species.columns = species
   .....: 
100 loops, best of 3: 2.55 ms per loop

看起来像Dan赢得了远射!

答案 2 :(得分:1)

据我所知,列中的数据不会改变,但只为每个相应的动物重复列。 I.E如果你只有一只老虎和一只狮子,你会想要一个结果数据帧与哺乳动物栏重复两次并改变标题?

在这种情况下,你可以这样做:

habitat_species = pd.DataFrame(0.0, index=range(1,11))
for key, value in lookupMap.iteritems():
    habitat_species[key] = habitat_family[value]

这将在habitat_species数据框中创建一个新列,其名称由key指定,并指定habitat_family数据框中相应列中的所有值,其名称已给出按value

答案 3 :(得分:1)

这可能是最为潘通的:

In [1]: habitat_species.apply(lambda x: habitat_family[lookupMap[x.name]])
Out[1]:
    tiger  lion  mosquito  ladybug  locust  seal  seabass  shark  dolphin
1     101   101       345      345     345   101      625    625      101
2     123   123       928      928     928   123      254    254      123
3     523   523       183      183     183   523      929    929      523
4     562   562       645      645     645   562      827    827      562
5     546   546       113      113     113   546      102    102      546
6     213   213       942      942     942   213      295    295      213
7     562   562       689      689     689   562      174    174      562
8     234   234       539      539     539   234      777    777      234
9     987   987       789      789     789   987      123    123      987
10    901   901       814      814     814   901      763    763      901

%timeit habitat_species.apply(lambda x: habitat_family[lookupMap[x.name]])
1000 loops, best of 3: 1.57 ms per loop
相关问题