2016-08-03 25 views
12

Bei einer Matrix aus einem SFrame erhalten:Effiziente Weise die einzigartigen Werte von 2 oder mehr Spalten in einem Dataframe

>>> from sframe import SFrame 
>>> sf =SFrame({'x':[1,1,2,5,7], 'y':[2,4,6,8,2], 'z':[2,5,8,6,2]}) 
>>> sf 
Columns: 
    x int 
    y int 
    z int 

Rows: 5 

Data: 
+---+---+---+ 
| x | y | z | 
+---+---+---+ 
| 1 | 2 | 2 | 
| 1 | 4 | 5 | 
| 2 | 6 | 8 | 
| 5 | 8 | 6 | 
| 7 | 2 | 2 | 
+---+---+---+ 
[5 rows x 3 columns] 

Ich mag die eindeutigen Werte für die x und y Spalten bekommen, und ich kann es tun als solche:

>>> sf['x'].unique().append(sf['y'].unique()).unique() 
dtype: int 
Rows: 7 
[2, 8, 5, 4, 1, 7, 6] 

so kann ich die einzigartigen Werte von x und eindeutige Werte von y erhalten sie dann anhängen und die einzigartigen Werte der beigefügten Liste erhalten.

konnte ich es auch tun, als solche:

>>> sf['x'].append(sf['y']).unique() 
dtype: int 
Rows: 7 
[2, 8, 5, 4, 1, 7, 6] 

Aber auf diese Weise, wenn meine x und y Spalten mit vielen Duplikaten sind riesig, wäre ich es in einen sehr großen Container anhängen, bevor die einzigartigen bekommen .

Gibt es einen effizienteren Weg, um die eindeutigen Werte einer kombinierten Spalten aus 2 oder mehr Spalten in einem SFrame zu erhalten?

Was ist die Äquivalenz in Pandas der effizienten Möglichkeit, eindeutige Werte aus 2 oder mehr Spalten in pandas zu erhalten?

+0

Ist die Reihenfolge der Elemente in der Ausgabe von Bedeutung? Wäre es in Ordnung, die Ausgabe als Liste oder Array zu haben? – Divakar

+0

[SFrame's API] (https://turi.com/products/create/docs/generated/graphlab.SFrame.html) ist ziemlich schlecht im Vergleich zu Pandas API, also glaube ich nicht, dass Sie es in viel mehr tun können effizienter im Vergleich zu Ihren Lösungen. Vielleicht ist es an der Zeit, [Apache Spark] (http://spark.apache.org/) zu verwenden? – MaxU

Antwort

2

Ich habe SFrame nicht aber auf pd.DataFrame getestet:

sf[["x", "y"]].stack().value_counts().index.tolist() 
    [2, 1, 8, 7, 6, 5, 4] 
+0

Schnelle Frage, in diesem Fall wird die eine Spalte (mit Duplikat) an eine andere (mit Duplikat) angehängt, bevor '.value_counts()' richtig gemacht wird? – alvas

+0

Ja, der Code stapelt die Daten, um auf die zugrunde liegenden Werte zuzugreifen. – Merlin

+0

Es funktioniert, ich habe upvoted. Aber ich denke, eine sframe-Antwort wäre angemessener. Hoffe, dass Sie nichts dagegen haben =) – alvas

1

Obwohl ich weiß nicht, wie es in SFrame zu tun, hier ist eine längere Erklärung von @ Merlin Antwort:

>>> import pandas as pd 
>>> df = pd.DataFrame({'x':[1,1,2,5,7], 'y':[2,4,6,8,2], 'z':[2,5,8,6,2]}) 
>>> df[['x', 'y']] 
    x y 
0 1 2 
1 1 4 
2 2 6 
3 5 8 
4 7 2 

Um nur Spalten X und Y

>>> df[['x', 'y']] # Extract only columns x and y 
    x y 
0 1 2 
1 1 4 
2 2 6 
3 5 8 
4 7 2 

Um stapeln die 2 Spalten pro Zeile in 1 co zu extrahieren lumn Reihe, während noch in der Lage zu sein, sie als Wörterbuch zuzugreifen:

>>> df[['x', 'y']].stack()      
0 x 1 
    y 2 
1 x 1 
    y 4 
2 x 2 
    y 6 
3 x 5 
    y 8 
4 x 7 
    y 2 
dtype: int64 
>>> df[['x', 'y']].stack()[0]  
x 1 
y 2 
dtype: int64 
>>> df[['x', 'y']].stack()[0]['x'] 
1 
>>> df[['x', 'y']].stack()[0]['y'] 
2 

Zählen Sie die einzelnen Werte aller Elemente innerhalb der kombinierten Spalten:

>>> df[['x', 'y']].stack().value_counts() # index(i.e. keys)=elements, Value=counts 
2 3 
1 2 
8 1 
7 1 
6 1 
5 1 
4 1 

auf den Index und zählt zuzugreifen:

>>> df[['x', 'y']].stack().value_counts().index  
Int64Index([2, 1, 8, 7, 6, 5, 4], dtype='int64') 
>>> df[['x', 'y']].stack().value_counts().values 
array([3, 2, 1, 1, 1, 1, 1]) 

Konvertieren in eine Liste:

>>> sf[["x", "y"]].stack().value_counts().index.tolist() 
[2, 1, 8, 7, 6, 5, 4] 

Noch eine SFrame Antwort wäre auch toll. Die gleiche Syntax funktioniert nicht für SFrame.

+0

IIUC, 'stack()' wird sehr wahrscheinlich die zugrunde liegenden Daten kopieren - wahrscheinlich etwas, das Sie vermeiden möchten. – ptrj

2

Der einfachste Weg, ich denken kann, ist auf eine numpy Array dann finden eindeutige Werte

np.unique(sf[['x', 'y']].to_numpy()) 

array([1, 2, 4, 5, 6, 7, 8]) 

konvertieren Wenn Sie es in einem sframe benötigt

SFrame({'xy_unique': np.unique(sf[['x', 'y']].to_numpy())}) 

enter image description here

2

SFrame

Ich habe kein SFrame verwendet und weiß nicht, unter welchen Bedingungen es Daten kopiert. (Wird die Auswahl sf['x'] oder append Daten in den Speicher kopiert?). Es gibt pack_columns und stack Methoden in SFrame und wenn sie Daten nicht kopieren, dann sollte diese Arbeit:

sf[['x', 'y']].pack_columns(new_column_name='N').stack('N').unique() 

Pandas

Wenn Sie Ihre Daten in den Speicher passen, dann können Sie wahrscheinlich tun es in Pandas effizient ohne zusätzliche Kopie.

# copies the data to memory 
df = sf[['x', 'y']].to_dataframe() 

# a reference to the underlying numpy array (no copy) 
vals = df.values 

# 1d array: 
# (numpy.ravel doesn't copy if it doesn't have to - it depends on the data layout) 
if np.isfortran(vals): 
    vals_1d = vals.ravel(order='F') 
else: 
    vals_1d = vals.ravel(order='C') 

uniques = pd.unique(vals_1d) 

Pandas des unique ist effizienter als numpy der np.unique, weil es sortieren nicht.

2

Werfen Sie einen Blick auf this answer zu einer ähnlichen Frage. Beachten Sie, dass die Funktion der Pandas pd.unique wesentlich schneller ist als die von Numpy.

>>> pd.unique(sf[['x','y']].values.ravel()) 
array([2, 8, 5, 4, 1, 7, 6], dtype=object) 
1

Hier ist eine kleine Benchmark zwischen drei möglichen Methoden:

from sframe import SFrame 
import numpy as np 
import pandas as pd 
import timeit 

sf = SFrame({'x': [1, 1, 2, 5, 7], 'y': [2, 4, 6, 8, 2], 'z': [2, 5, 8, 6, 2]}) 


def f1(sf): 
    return sf['x'].unique().append(sf['y'].unique()).unique() 


def f2(sf): 
    return sf['x'].append(sf['y']).unique() 


def f3(sf): 
    return np.unique(sf[['x', 'y']].to_numpy()) 

N = 1000 

print timeit.timeit('f1(sf)', setup='from __main__ import f1, sf', number=N) 
print timeit.timeit('f2(sf)', setup='from __main__ import f2, sf', number=N) 
print timeit.timeit('f3(sf)', setup='from __main__ import f3, sf', number=N) 

# 13.3195129933 
# 4.66225642657 
# 3.65669089489 
# [Finished in 23.6s] 

Benchmark mit python2.7.11 x64 auf Windows7 + i7_2.6ghz

Fazit: Ich Sie np.unique verwenden würde vorschlagen, das ist grundsätzlich f3.