2017-07-26 26 views
14

Załóżmy, że mam dwie dataframes d1 i d2przeplatają się dwa dataframes

d1 = pd.DataFrame(np.ones((3, 3), dtype=int), list('abc'), [0, 1, 2]) 
d2 = pd.DataFrame(np.zeros((3, 2), dtype=int), list('abc'), [3, 4]) 

d1 

    0 1 2 
a 1 1 1 
b 1 1 1 
c 1 1 1 

d2 

    3 4 
a 0 0 
b 0 0 
c 0 0 

Co jest łatwym i uogólniony sposób przeplatają kolumny dwa dataframes. Możemy założyć, że liczba kolumn w d2 jest zawsze o jeden mniej niż liczba kolumn w d1. A wskaźniki są takie same.

Chcę to:

pd.concat([d1[0], d2[3], d1[1], d2[4], d1[2]], axis=1) 

    0 3 1 4 2 
a 1 0 1 0 1 
b 1 0 1 0 1 
c 1 0 1 0 1 

Odpowiedz

12

Korzystanie pd.concat połączyć DataFrames i toolz.interleave zmienić kolejność kolumn:

from toolz import interleave 

pd.concat([d1, d2], axis=1)[list(interleave([d1, d2]))] 

Wynikiem jest zgodnie z oczekiwaniami:

0 3 1 4 2 
a 1 0 1 0 1 
b 1 0 1 0 1 
c 1 0 1 0 1 
+0

Genialny jak zawsze ...Już zacząłem używać 'cytoolz' na twoją rekomendację (-: – piRSquared

+0

Ta odpowiedź prawie wydawała mi się oszustwem, ponieważ funkcja' przeplata' jest specjalnie dostosowana do danej operacji .. Tak, jestem wielkim fanem 'toolz' /' cytoolz' Pamiętam, że cieszę się widząc, że używasz 'cytoolz' w jednym z twoich pytań chwilę temu! – root

+0

Użyłem go już https://stackoverflow.com/a/45453058/2336654 – piRSquared

5

przeplatają kolumny:

c = np.empty((d1.columns.size + d2.columns.size,), dtype=object) 
c[0::2], c[1::2] = d1.columns, d2.columns 

teraz zrobić JOIN i re-zlecenia z logicznego indeksowania:

d1.join(d2)[c] 

    0 3 1 4 2 
a 1 0 1 0 1 
b 1 0 1 0 1 
c 1 0 1 0 1 

Możesz wolą pd.concat w przypadku obsługi wielu ramek danych.

1

napisać funkcję do abstrakcyjna dala rodzajową seryjnej-uporządkować

from itertools import zip_longest 
def weave(df1, df2): 
    col1 = df1.columns 
    col2 = df2.columns 
    weaved = [col for zipped in zip_longest(col1,col2) 
       for col in zipped 
       if col is not None] 
    return pd.concat([df1, df2], axis=1)[weaved] 

weave(d1, d2) 
# Output: 
    0 3 1 4 2 
a 1 0 1 0 1 
b 1 0 1 0 1 
c 1 0 1 0 1 
6

Oto jedno podejście NumPy h -

def numpy_interweave(d1, d2): 
    c1 = list(d1.columns) 
    c2 = list(d2.columns) 
    N = (len(c1)+len(c2)) 
    cols = [None]*N 
    cols[::2] = c1 
    cols[1::2] = c2 

    out_dtype = np.result_type(d1.values.dtype, d2.values.dtype) 
    out = np.empty((d1.shape[0],N),dtype=out_dtype) 
    out[:,::2] = d1.values 
    out[:,1::2] = d2.values 

    df_out = pd.DataFrame(out, columns=cols, index=d1.index) 
    return df_out 

Sample Run -

In [346]: d1 
Out[346]: 
    x y z 
a 6 7 4 
b 3 5 6 
c 4 6 2 

In [347]: d2 
Out[347]: 
    p q 
a 4 2 
b 7 7 
c 7 2 

In [348]: numpy_interweave(d1, d2) 
Out[348]: 
    x p y q z 
a 6 4 7 2 4 
b 3 7 5 7 6 
c 4 7 6 2 2 
1

możemy użyć itertools.zip_longest:

In [75]: from itertools import zip_longest 

In [76]: cols = pd.Series(np.concatenate(list(zip_longest(d1.columns, d2.columns)))).dropna() 

In [77]: cols 
Out[77]: 
0 0 
1 3 
2 1 
3 4 
4 2 
dtype: object 

In [78]: df = pd.concat([d1, d2], axis=1)[cols] 

In [79]: df 
Out[79]: 
    0 3 1 4 2 
a 1 0 1 0 1 
b 1 0 1 0 1 
c 1 0 1 0 1 
1

Moje rozwiązanie było użyć pd.DataFrame.insert upewniając się, aby wstawić z powrotem pierwszego

df = d1.copy() 
for i in range(d2.shape[1], 0, -1): 
    df.insert(i, d2.columns[i - 1], d2.iloc[:, i - 1]) 

df 

    0 3 1 4 2 
a 1 0 1 0 1 
b 1 0 1 0 1 
c 1 0 1 0 1 
1

Przepis itertools roundrobin ma charakter przeplatania. Ta opcja pozwala na wybór pomiędzy bezpośrednio realizacji receptury z Python docs lub importowania pakietu innych firm, takich jak more_itertools który implementuje przepis dla Ciebie:

from more_itertools import roundrobin 

pd.concat([d1, d2], axis=1)[list(roundrobin(d1, d2))] 

# Output 
    0 3 1 4 2 
a 1 0 1 0 1 
b 1 0 1 0 1 
c 1 0 1 0 1 

Zainspirowany odpowiedź @ roota, indeksy kolumn są przeplatany i służy do dzielenia połączonej ramki DataFrame.