2016-05-16 8 views
2

Ich bin neu in Pandas, und ich versuche, mehrere Spalten im Gegensatz zu nur einer zuordnen. This page zeigt mir, wie man es mit einer pd.Series macht, aber ich kann nicht herausfinden, wie man mehrere columns abbildet.Mapping Datenrahmen nicht Serie Pandas

Hier ist meine zwei DataFrames Ich versuche map.

data2=pd.DataFrame(np.random.randn(5,2),index=range(0,5),columns=['x','y']) 
data2['Cluster']=['A','B','A','B','C'] 
centers2=pd.DataFrame(np.random.randint(0,10,size=(3,2)),index= ['A','B','C'],columns=['x','y']) 

Hier data2 wie folgt aussieht:

data2 

    x   y    Cluster 
0 0.151212 -0.168855  A 
1 -0.078935 1.933378  B 
2 -0.388903 0.444610  A 
3 0.622089 1.609730  B 
4 -0.346856 1.095834  C 

und centers2 wie folgt aussieht:

centers2 
    x y 
A 6 4 
B 6 0 
C 4 1 

Ich möchte zwei separate Spalten in data2 erstellen, mit dem entsprechenden center2 Matching. Hier ist meine Hand-Versuch

data2['Centers.x']=[6,6,6,6,4] 
data2['Centers.y']=[4,0,4,0,1] 
data2 
      x   y Cluster Centers.x Centers.y 
0 0.151212 -0.168855  A   6   4 
1 -0.078935 1.933378  B   6   0 
2 -0.388903 0.444610  A   6   4 
3 0.622089 1.609730  B   6   0 
4 -0.346856 1.095834  C   4   1 

Wie kann ich dies mit der map Funktion? (Ich weiß, wie diese Loops zu tun, ich brauche eine vektorisiert Lösung.)

Antwort

1

.merge() am nächsten kommt pd.Series.map() für pd.DataFrame. Sie können überlappenden Spalten mithilfe des Schlüsselworts suffixes=[] einen benutzerdefinierten Header hinzufügen, z. B. suffices=['', '_centers'].

Hinweis pd.Series hat keine .merge() und pd.DataFrame hat keine .map().

Mit

data2 
      x   y Cluster 
0 -1.406449 -0.244859  A 
1 1.002103 0.214346  B 
2 0.353894 0.353995  A 
3 1.249199 -0.661904  B 
4 0.623962 -1.754789  C 

centers2 
    x y 
A 0 9 
B 6 9 
C 0 6 

Sie erhalten:

data2.merge(centers2, left_on='Cluster', right_index=True, suffixes=['', '_centers']).sort_index() 

      x   y Cluster x_centers y_centers 
0 -1.406449 -0.244859  A   0   9 
1 1.002103 0.214346  B   6   9 
2 0.353894 0.353995  A   0   9 
3 1.249199 -0.661904  B   6   9 
4 0.623962 -1.754789  C   0   6 

Es gibt auch die .join() Option ist, die eine andere Art und Weise ist .merge() zuzugreifen oder pd.concat() wenn .merge() auf index für beide DataFrame ist - von der Quelle:

def join(self, other, on=None, how='left', lsuffix='', rsuffix='', 
     sort=False): 
    return self._join_compat(other, on=on, how=how, lsuffix=lsuffix, 
          rsuffix=rsuffix, sort=sort) 

def _join_compat(self, other, on=None, how='left', lsuffix='', rsuffix='', 
       sort=False): 
    from pandas.tools.merge import merge, concat 

    if isinstance(other, Series): 
     if other.name is None: 
      raise ValueError('Other Series must have a name') 
     other = DataFrame({other.name: other}) 

    if isinstance(other, DataFrame): 
     return merge(self, other, left_on=on, how=how, 
        left_index=on is None, right_index=True, 
        suffixes=(lsuffix, rsuffix), sort=sort) 
    else: 
     if on is not None: 
      raise ValueError('Joining multiple DataFrames only supported' 
          ' for joining on index') 
+0

Ja, es ist am einfachsten, aber die Sortierung wurde geändert. – jezrael

+0

Das ist richtig, hinzugefügt '.sort_index()' um sicherzustellen, dass sortiert wird. – Stefan

+0

Würde gerne - wo ist es? – Stefan

1

Sie können concat mit map:

print pd.concat([data2.x, data2.y, 
       data2.Cluster, 
       data2.Cluster.map(centers2.x.to_dict()), 
       data2.Cluster.map(centers2.y.to_dict())], 
       axis=1, 
       keys=['x','y','Cluster','Centers.x','Centers.y']) 

      x   y Cluster Centers.x Centers.y 
0 -0.247322 -0.699005  A   6   5 
1 -0.026692 0.551841  B   1   4 
2 -1.730480 -0.170510  A   6   5 
3 0.814357 -0.204729  B   1   4 
4 2.387925 -0.503993  C   1   0 

Lösung mit join: docs

print data2.join(centers2, on='Cluster', rsuffix ='_centers') 

      x   y Cluster x_centers y_centers 
0 -0.247322 -0.699005  A   6   5 
1 -0.026692 0.551841  B   1   4 
2 -1.730480 -0.170510  A   6   5 
3 0.814357 -0.204729  B   1   4 
4 2.387925 -0.503993  C   1   0 

Eine andere Lösung mit merge ist das gleiche wie join, aber 2 Parameter werden hinzugefügt:

Timings:

len(df)=5k:

data2 = pd.concat([data2]*1000).reset_index(drop=True) 

def root(data2, centers2):     
    data2['Centers.x'] = data2.apply(lambda row: centers2.get_value(row['Cluster'], 'x'), axis=1) 
    data2['Centers.y'] = data2.apply(lambda row: centers2.get_value(row['Cluster'], 'y'), axis=1)     
    return data2 

In [117]: %timeit root(data2, centers2) 
1 loops, best of 3: 267 ms per loop 

In [118]: %timeit data2.merge(centers2, left_on='Cluster', right_index=True, suffixes=['', '_centers'], sort=False, how='left') 
1000 loops, best of 3: 1.71 ms per loop 

In [119]: %timeit data2.join(centers2, on='Cluster', rsuffix ='_centers', sort=False, how='left') 
1000 loops, best of 3: 1.71 ms per loop 

In [120]: %timeit pd.concat([data2.x, data2.y, data2.Cluster, data2.Cluster.map(centers2.x.to_dict()), data2.Cluster.map(centers2.y.to_dict())], axis=1, keys=['x','y','Cluster','Centers.x','Centers.y']) 
100 loops, best of 3: 2.15 ms per loop 

In [121]: %timeit data2.merge(centers2, left_on='Cluster', right_index=True, suffixes=['', '_centers']).sort_index() 
100 loops, best of 3: 2.68 ms per loop 
+0

Zeit hinzugefügt von 'Stefan Jansen' Lösung. – jezrael