2016-08-03 18 views
12

Biorąc pod uwagę macierz z SFrame:Skuteczny sposób na uzyskanie unikalnych wartości od 2 lub więcej kolumn w 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] 

chcę uzyskać unikatowe wartości dla x i y kolumn i mogę to zrobić takie jak:

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

ten sposób uzyskać unikalne wartości X i unikalne wartości y, a następnie dołączyć je i uzyskać unikalne wartości załączonej listy.

mogę też zrobić to w następujący sposób:

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

Ale w ten sposób, jeśli x i y kolumny są ogromne z dużą ilością powtórzeń, byłbym dołączenie go w bardzo wielkim pojemniku przed uzyskaniem wyjątkowy .

Czy istnieje skuteczniejszy sposób uzyskania unikatowych wartości połączonych kolumn utworzonych z co najmniej dwóch kolumn w ramce SFrame?

Jaka jest równoważność w pandach efektywnego sposobu uzyskiwania unikatowych wartości z 2 lub więcej kolumn w pandas?

+0

Czy kolejność elementów wyjściowych ma znaczenie? Czy byłoby dobrze mieć wynik jako listę lub tablicę? – Divakar

+0

[Interfejs API SFrame] (https://turi.com/products/create/docs/generated/graphlab.SFrame.html) jest dość słaba w porównaniu do Pandas API, więc nie sądzę, że można to zrobić w znacznie więcej skuteczny sposób w porównaniu do twoich rozwiązań. Może czas rozważyć użycie [Apache Spark] (http://spark.apache.org/)? – MaxU

Odpowiedz

2

Nie mam sframe ale testowane na pd.DataFrame:

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

Szybkie pytanie, w tym przypadku jedna kolumna (z duplikatem) jest dołączana do innej (z duplikatem) przed wykonaniem '.value_counts()' w prawo? – alvas

+0

Tak, kod układa dane, aby uzyskać dostęp do wartości bazowych. – Merlin

+0

Działa, przeszedłem. Ale myślę, że bardziej odpowiednia byłaby odpowiedź sframe. Mam nadzieję, że nie przeszkadza Ci =) – alvas

1

Chociaż nie wiem, jak to zrobić w sframe, tutaj jest już wyjaśnienie @ odpowiedź Merlina:

>>> 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 

wyodrębniania tylko kolumny X i 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 

układanie 2 kolumny w rzędzie w 1 CO lumn wiersz, podczas gdy wciąż jest w stanie do nich dostęp w słowniku:

>>> 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 

policzyć poszczególne wartości wszystkich elementów w połączeniu kolumny:

>>> 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 

Aby uzyskać dostęp liczy się indeks i:

>>> 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]) 

Konwersja do listy:

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

Nadal odpowiedź SFrame również byłaby świetna. Ta sama składnia nie działa dla SFrame.

+0

IIUC, 'stack()' najprawdopodobniej skopiuje podstawowe dane - prawdopodobnie coś, czego chciałbyś uniknąć. – ptrj

2

Najprostszym sposobem mogę myśleć jest konwersja do numpy tablicy następnie znaleźć unikalne wartości

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

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

Jeśli potrzebne go w sframe

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

enter image description here

2

sframe

Nie użyłem SFrame i nie wiem, na jakich warunkach kopiuje dane. (Czy wybór sf['x'] lub append kopiuje dane do pamięci?). Istnieje pack_columns i stack metody sframe i jeśli nie kopiować dane, to powinno działać:

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

pandy

jeśli dane pasują do pamięci to prawdopodobnie można to zrobić w pand sprawnie bez dodatkowej kopii.

# 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) 

pandy na unique jest bardziej efektywne niż numpy na np.unique ponieważ nie sortować.

2

Spójrz na this answer na podobne pytanie. Zauważ, że funkcja Pandy "pd.unique" jest znacznie szybsza niż Numpy.

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

Oto mały punkt odniesienia pomiędzy trzech możliwych sposobów:

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 przy użyciu python2.7.11 64 na Windows7 + i7_2.6ghz

Wniosek: Sugeruję użyć np.unique, to zasadniczo f3.