Làm thế nào để hủy bỏ (phát nổ) một cột trong DataFrame của gấu trúc?


116

Tôi có DataFrame sau đây trong đó một trong các cột là đối tượng (ô kiểu danh sách):

df=pd.DataFrame({'A':[1,2],'B':[[1,2],[1,2]]})
df
Out[458]: 
   A       B
0  1  [1, 2]
1  2  [1, 2]

Sản lượng mong đợi của tôi là:

   A  B
0  1  1
1  1  2
3  2  1
4  2  2

Tôi phải làm gì để đạt được điều này?


Câu hỏi liên quan

gấu trúc: Khi nội dung ô là danh sách, hãy tạo một hàng cho mỗi phần tử trong danh sách

Câu hỏi và câu trả lời hay nhưng chỉ xử lý một cột với danh sách (Trong câu trả lời của tôi, chức năng tự định nghĩa sẽ hoạt động cho nhiều cột, cũng có câu trả lời được chấp nhận là sử dụng tốn thời gian nhất apply, điều này không được khuyến khích, hãy kiểm tra thêm thông tin Khi nào tôi muốn để sử dụng pandas apply () trong mã của tôi? )


5
Liên quan, chuỗi unnesting: stackoverflow.com/q/48197234/4909087
cs95

5
Một số bài đăng liên quan: đây , đây , đây , đây , ...
Cleb

Câu trả lời:


182

Là một người dùng với cả hai Rpython, tôi đã gặp loại câu hỏi này một vài lần.

Trong R, chúng có hàm tích hợp từ gói tidyrđược gọi unnest. Nhưng trong Python( pandas) không có chức năng cài sẵn cho dạng câu hỏi này.

Tôi biết objectcác cột typeluôn làm cho dữ liệu khó chuyển đổi với một pandashàm '. Khi tôi nhận được dữ liệu như thế này, điều đầu tiên tôi nghĩ đến là 'làm phẳng' hoặc tách các cột.

Tôi đang sử dụng pandasvà các pythonchức năng cho loại câu hỏi này. Nếu bạn lo lắng về tốc độ của các giải pháp trên, hãy kiểm tra câu trả lời của user3483203, vì anh ấy đang sử dụng numpyvà hầu hết thời gian numpyđều nhanh hơn. Tôi đề nghị Cpythonnumbanếu tốc độ quan trọng trong trường hợp của bạn.


Phương pháp 0 [pandas> = 0,25]
Bắt đầu từ gấu trúc 0,25 , nếu bạn chỉ cần phát nổ một cột, bạn có thể sử dụng explodechức năng:

df.explode('B')

       A  B
    0  1  1
    1  1  2
    0  2  1
    1  2  2

Phương pháp 1
apply + pd.Series (dễ hiểu nhưng về mặt hiệu suất thì không nên.)

df.set_index('A').B.apply(pd.Series).stack().reset_index(level=0).rename(columns={0:'B'})
Out[463]: 
   A  B
0  1  1
1  1  2
0  2  1
1  2  2

Phương pháp 2
Sử dụng repeatvới hàm DataFrametạo, tạo lại khung dữ liệu của bạn (tốt ở hiệu suất, không tốt ở nhiều cột)

df=pd.DataFrame({'A':df.A.repeat(df.B.str.len()),'B':np.concatenate(df.B.values)})
df
Out[465]: 
   A  B
0  1  1
0  1  2
1  2  1
1  2  2


Ví dụ như phương pháp 2.1 ngoài A chúng ta có A.1 ..... An Nếu chúng ta vẫn sử dụng phương pháp ( Phương pháp 2 ) ở trên, chúng ta khó có thể tạo lại từng cột một.

Giải pháp: joinhoặc mergevới indexsau 'unnest' các cột đơn

s=pd.DataFrame({'B':np.concatenate(df.B.values)},index=df.index.repeat(df.B.str.len()))
s.join(df.drop('B',1),how='left')
Out[477]: 
   B  A
0  1  1
0  2  1
1  1  2
1  2  2

Nếu bạn cần thứ tự cột giống hệt như trước đây, hãy thêm reindexvào cuối.

s.join(df.drop('B',1),how='left').reindex(columns=df.columns)

Phương pháp 3
tạo lạilist

pd.DataFrame([[x] + [z] for x, y in df.values for z in y],columns=df.columns)
Out[488]: 
   A  B
0  1  1
1  1  2
2  2  1
3  2  2

Nếu nhiều hơn hai cột, hãy sử dụng

s=pd.DataFrame([[x] + [z] for x, y in zip(df.index,df.B) for z in y])
s.merge(df,left_on=0,right_index=True)
Out[491]: 
   0  1  A       B
0  0  1  1  [1, 2]
1  0  2  1  [1, 2]
2  1  1  2  [1, 2]
3  1  2  2  [1, 2]

Phương pháp 4
sử dụng reindex hoặcloc

df.reindex(df.index.repeat(df.B.str.len())).assign(B=np.concatenate(df.B.values))
Out[554]: 
   A  B
0  1  1
0  1  2
1  2  1
1  2  2

#df.loc[df.index.repeat(df.B.str.len())].assign(B=np.concatenate(df.B.values))

Phương pháp 5
khi danh sách chỉ chứa các giá trị duy nhất:

df=pd.DataFrame({'A':[1,2],'B':[[1,2],[3,4]]})
from collections import ChainMap
d = dict(ChainMap(*map(dict.fromkeys, df['B'], df['A'])))
pd.DataFrame(list(d.items()),columns=df.columns[::-1])
Out[574]: 
   B  A
0  1  1
1  2  1
2  3  2
3  4  2

Phương pháp 6
sử dụng numpycho hiệu suất cao:

newvalues=np.dstack((np.repeat(df.A.values,list(map(len,df.B.values))),np.concatenate(df.B.values)))
pd.DataFrame(data=newvalues[0],columns=df.columns)
   A  B
0  1  1
1  1  2
2  2  1
3  2  2

Phương pháp 7
sử dụng hàm cơ sở itertools cyclechain: Giải pháp python tinh khiết chỉ để giải trí

from itertools import cycle,chain
l=df.values.tolist()
l1=[list(zip([x[0]], cycle(x[1])) if len([x[0]]) > len(x[1]) else list(zip(cycle([x[0]]), x[1]))) for x in l]
pd.DataFrame(list(chain.from_iterable(l1)),columns=df.columns)
   A  B
0  1  1
1  1  2
2  2  1
3  2  2

Tổng quát hóa thành nhiều cột

df=pd.DataFrame({'A':[1,2],'B':[[1,2],[3,4]],'C':[[1,2],[3,4]]})
df
Out[592]: 
   A       B       C
0  1  [1, 2]  [1, 2]
1  2  [3, 4]  [3, 4]

Chức năng tự định nghĩa:

def unnesting(df, explode):
    idx = df.index.repeat(df[explode[0]].str.len())
    df1 = pd.concat([
        pd.DataFrame({x: np.concatenate(df[x].values)}) for x in explode], axis=1)
    df1.index = idx

    return df1.join(df.drop(explode, 1), how='left')


unnesting(df,['B','C'])
Out[609]: 
   B  C  A
0  1  1  1
0  2  2  1
1  3  3  2
1  4  4  2

Bỏ ghi chú theo cột

Tất cả phương pháp trên đang nói về việc mở rộng danh sách theo chiều dọc và bùng nổ, Nếu bạn cần mở rộng danh sách theo chiều ngang , Hãy kiểm tra với nhà pd.DataFramexây dựng

df.join(pd.DataFrame(df.B.tolist(),index=df.index).add_prefix('B_'))
Out[33]: 
   A       B       C  B_0  B_1
0  1  [1, 2]  [1, 2]    1    2
1  2  [3, 4]  [3, 4]    3    4

Đã cập nhật chức năng

def unnesting(df, explode, axis):
    if axis==1:
        idx = df.index.repeat(df[explode[0]].str.len())
        df1 = pd.concat([
            pd.DataFrame({x: np.concatenate(df[x].values)}) for x in explode], axis=1)
        df1.index = idx

        return df1.join(df.drop(explode, 1), how='left')
    else :
        df1 = pd.concat([
                         pd.DataFrame(df[x].tolist(), index=df.index).add_prefix(x) for x in explode], axis=1)
        return df1.join(df.drop(explode, 1), how='left')

Kiểm tra đầu ra

unnesting(df, ['B','C'], axis=0)
Out[36]: 
   B0  B1  C0  C1  A
0   1   2   1   2  1
1   3   4   3   4  2

Chúng không thực sự hoạt động. ValueError: zero-dimensional arrays cannot be concatenated. Ngoài ra, một số ít trong số này thậm chí cố gắng tổng quát hóa thành khung dữ liệu rộng hơn. Những cái yêu cầu bạn phải biết df của bạn có bao nhiêu cột trước thời hạn.
Tristan Brown

@TristanBrown là bạn không có thứ nguyên, bạn không nên vượt qua sự bùng nổ, bạn nên thả nó trước khi phát nổ, ví dụ như []nên thả, bạn đã thực sự thử ví dụ từ tôi chưa? Hoặc bạn có tình hình khác nhau?
BEN_YO

1
@TristanBrown cũng là chú gấu trúc có chức năng tích hợp phát nổ, nếu điều này không phù hợp với bạn, có nghĩa là câu hỏi của bạn đã khác.
BEN_YO

43

lựa chọn 1

Nếu tất cả các danh sách con trong cột khác có cùng độ dài, numpycó thể là một tùy chọn hiệu quả ở đây:

vals = np.array(df.B.values.tolist())    
a = np.repeat(df.A, vals.shape[1])

pd.DataFrame(np.column_stack((a, vals.ravel())), columns=df.columns)

   A  B
0  1  1
1  1  2
2  2  1
3  2  2

Lựa chọn 2

Nếu danh sách phụ có độ dài khác nhau, bạn cần thực hiện thêm một bước:

vals = df.B.values.tolist()
rs = [len(r) for r in vals]    
a = np.repeat(df.A, rs)

pd.DataFrame(np.column_stack((a, np.concatenate(vals))), columns=df.columns)

   A  B
0  1  1
1  1  2
2  2  1
3  2  2

Lựa chọn 3

Tôi đã chụp ảnh khái quát điều này để làm phẳng Ncác cột và Mcột gạch , tôi sẽ làm việc sau để làm cho nó hiệu quả hơn:

df = pd.DataFrame({'A': [1,2,3], 'B': [[1,2], [1,2,3], [1]],
                   'C': [[1,2,3], [1,2], [1,2]], 'D': ['A', 'B', 'C']})

   A          B          C  D
0  1     [1, 2]  [1, 2, 3]  A
1  2  [1, 2, 3]     [1, 2]  B
2  3        [1]     [1, 2]  C

def unnest(df, tile, explode):
    vals = df[explode].sum(1)
    rs = [len(r) for r in vals]
    a = np.repeat(df[tile].values, rs, axis=0)
    b = np.concatenate(vals.values)
    d = np.column_stack((a, b))
    return pd.DataFrame(d, columns = tile +  ['_'.join(explode)])

unnest(df, ['A', 'D'], ['B', 'C'])

    A  D B_C
0   1  A   1
1   1  A   2
2   1  A   1
3   1  A   2
4   1  A   3
5   2  B   1
6   2  B   2
7   2  B   3
8   2  B   1
9   2  B   2
10  3  C   1
11  3  C   1
12  3  C   2

Chức năng

def wen1(df):
    return df.set_index('A').B.apply(pd.Series).stack().reset_index(level=0).rename(columns={0: 'B'})

def wen2(df):
    return pd.DataFrame({'A':df.A.repeat(df.B.str.len()),'B':np.concatenate(df.B.values)})

def wen3(df):
    s = pd.DataFrame({'B': np.concatenate(df.B.values)}, index=df.index.repeat(df.B.str.len()))
    return s.join(df.drop('B', 1), how='left')

def wen4(df):
    return pd.DataFrame([[x] + [z] for x, y in df.values for z in y],columns=df.columns)

def chris1(df):
    vals = np.array(df.B.values.tolist())
    a = np.repeat(df.A, vals.shape[1])
    return pd.DataFrame(np.column_stack((a, vals.ravel())), columns=df.columns)

def chris2(df):
    vals = df.B.values.tolist()
    rs = [len(r) for r in vals]
    a = np.repeat(df.A.values, rs)
    return pd.DataFrame(np.column_stack((a, np.concatenate(vals))), columns=df.columns)

Thời gian

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from timeit import timeit

res = pd.DataFrame(
       index=['wen1', 'wen2', 'wen3', 'wen4', 'chris1', 'chris2'],
       columns=[10, 50, 100, 500, 1000, 5000, 10000],
       dtype=float
)

for f in res.index:
    for c in res.columns:
        df = pd.DataFrame({'A': [1, 2], 'B': [[1, 2], [1, 2]]})
        df = pd.concat([df]*c)
        stmt = '{}(df)'.format(f)
        setp = 'from __main__ import df, {}'.format(f)
        res.at[f, c] = timeit(stmt, setp, number=50)

ax = res.div(res.min()).T.plot(loglog=True)
ax.set_xlabel("N")
ax.set_ylabel("time (relative)")

Hiệu suất

nhập mô tả hình ảnh ở đây


3
Thật thú vị, sẽ rất vui nếu biết so sánh với df.explodephương pháp mới .
Paul Rougieux


9

Một cách thay thế là áp dụng công thức meshgrid trên các hàng của cột để hủy bỏ:

import numpy as np
import pandas as pd


def unnest(frame, explode):
    def mesh(values):
        return np.array(np.meshgrid(*values)).T.reshape(-1, len(values))

    data = np.vstack(mesh(row) for row in frame[explode].values)
    return pd.DataFrame(data=data, columns=explode)


df = pd.DataFrame({'A': [1, 2], 'B': [[1, 2], [1, 2]]})
print(unnest(df, ['A', 'B']))  # base
print()

df = pd.DataFrame({'A': [1, 2], 'B': [[1, 2], [3, 4]], 'C': [[1, 2], [3, 4]]})
print(unnest(df, ['A', 'B', 'C']))  # multiple columns
print()

df = pd.DataFrame({'A': [1, 2, 3], 'B': [[1, 2], [1, 2, 3], [1]],
                   'C': [[1, 2, 3], [1, 2], [1, 2]], 'D': ['A', 'B', 'C']})

print(unnest(df, ['A', 'B']))  # uneven length lists
print()
print(unnest(df, ['D', 'B']))  # different types
print()

Đầu ra

   A  B
0  1  1
1  1  2
2  2  1
3  2  2

   A  B  C
0  1  1  1
1  1  2  1
2  1  1  2
3  1  2  2
4  2  3  3
5  2  4  3
6  2  3  4
7  2  4  4

   A  B
0  1  1
1  1  2
2  2  1
3  2  2
4  2  3
5  3  1

   D  B
0  A  1
1  A  2
2  B  1
3  B  2
4  B  3
5  C  1

3

5 xu của tôi:

df[['B', 'B2']] = pd.DataFrame(df['B'].values.tolist())

df[['A', 'B']].append(df[['A', 'B2']].rename(columns={'B2': 'B'}),
                      ignore_index=True)

và 5 cái khác

df[['B1', 'B2']] = pd.DataFrame([*df['B']]) # if values.tolist() is too boring

(pd.wide_to_long(df.drop('B', 1), 'B', 'A', '')
 .reset_index(level=1, drop=True)
 .reset_index())

cả hai đều dẫn đến như nhau

   A  B
0  1  1
1  2  1
2  1  2
3  2  2

2

Bởi vì thông thường độ dài danh sách con là khác nhau và việc tham gia / hợp nhất tốn kém hơn nhiều về tính toán. Tôi đã thử lại phương pháp cho danh sách con có độ dài khác nhau và các cột bình thường hơn.

MultiIndex cũng nên là một cách dễ viết hơn và có hiệu suất gần giống như cách numpy.

Đáng ngạc nhiên, trong cách hiểu triển khai của tôi có hiệu suất tốt nhất.

def stack(df):
    return df.set_index(['A', 'C']).B.apply(pd.Series).stack()


def comprehension(df):
    return pd.DataFrame([x + [z] for x, y in zip(df[['A', 'C']].values.tolist(), df.B) for z in y])


def multiindex(df):
    return pd.DataFrame(np.concatenate(df.B.values), index=df.set_index(['A', 'C']).index.repeat(df.B.str.len()))


def array(df):
    return pd.DataFrame(
        np.column_stack((
            np.repeat(df[['A', 'C']].values, df.B.str.len(), axis=0),
            np.concatenate(df.B.values)
        ))
    )


import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from timeit import timeit

res = pd.DataFrame(
    index=[
        'stack',
        'comprehension',
        'multiindex',
        'array',
    ],
    columns=[1000, 2000, 5000, 10000, 20000, 50000],
    dtype=float
)

for f in res.index:
    for c in res.columns:
        df = pd.DataFrame({'A': list('abc'), 'C': list('def'), 'B': [['g', 'h', 'i'], ['j', 'k'], ['l']]})
        df = pd.concat([df] * c)
        stmt = '{}(df)'.format(f)
        setp = 'from __main__ import df, {}'.format(f)
        res.at[f, c] = timeit(stmt, setp, number=20)

ax = res.div(res.min()).T.plot(loglog=True)
ax.set_xlabel("N")
ax.set_ylabel("time (relative)")

Hiệu suất

Thời gian tương đối của mỗi phương pháp


2

Tôi đã khái quát vấn đề một chút để có thể áp dụng cho nhiều cột hơn.

Tóm tắt những gì giải pháp của tôi thực hiện:

In[74]: df
Out[74]: 
    A   B             C             columnD
0  A1  B1  [C1.1, C1.2]                D1
1  A2  B2  [C2.1, C2.2]  [D2.1, D2.2, D2.3]
2  A3  B3            C3        [D3.1, D3.2]

In[75]: dfListExplode(df,['C','columnD'])
Out[75]: 
    A   B     C columnD
0  A1  B1  C1.1    D1
1  A1  B1  C1.2    D1
2  A2  B2  C2.1    D2.1
3  A2  B2  C2.1    D2.2
4  A2  B2  C2.1    D2.3
5  A2  B2  C2.2    D2.1
6  A2  B2  C2.2    D2.2
7  A2  B2  C2.2    D2.3
8  A3  B3    C3    D3.1
9  A3  B3    C3    D3.2

Toàn bộ ví dụ:

Vụ nổ thực tế được thực hiện trong 3 dòng. Phần còn lại là mỹ phẩm (nổ nhiều cột, xử lý dây thay cho danh sách trong cột nổ, ...).

import pandas as pd
import numpy as np

df=pd.DataFrame( {'A': ['A1','A2','A3'],
                  'B': ['B1','B2','B3'],
                  'C': [ ['C1.1','C1.2'],['C2.1','C2.2'],'C3'],
                  'columnD': [ 'D1',['D2.1','D2.2', 'D2.3'],['D3.1','D3.2']],
                  })
print('df',df, sep='\n')

def dfListExplode(df, explodeKeys):
    if not isinstance(explodeKeys, list):
        explodeKeys=[explodeKeys]
    # recursive handling of explodeKeys
    if len(explodeKeys)==0:
        return df
    elif len(explodeKeys)==1:
        explodeKey=explodeKeys[0]
    else:
        return dfListExplode( dfListExplode(df, explodeKeys[:1]), explodeKeys[1:])
    # perform explosion/unnesting for key: explodeKey
    dfPrep=df[explodeKey].apply(lambda x: x if isinstance(x,list) else [x]) #casts all elements to a list
    dfIndExpl=pd.DataFrame([[x] + [z] for x, y in zip(dfPrep.index,dfPrep.values) for z in y ], columns=['explodedIndex',explodeKey])
    dfMerged=dfIndExpl.merge(df.drop(explodeKey, axis=1), left_on='explodedIndex', right_index=True)
    dfReind=dfMerged.reindex(columns=list(df))
    return dfReind

dfExpl=dfListExplode(df,['C','columnD'])
print('dfExpl',dfExpl, sep='\n')

Tín dụng cho câu trả lời của WeNYoBen


2

Thiết lập sự cố

Giả sử có nhiều cột với các đối tượng có độ dài khác nhau bên trong nó

df = pd.DataFrame({
    'A': [1, 2],
    'B': [[1, 2], [3, 4]],
    'C': [[1, 2], [3, 4, 5]]
})

df

   A       B          C
0  1  [1, 2]     [1, 2]
1  2  [3, 4]  [3, 4, 5]

Khi độ dài giống nhau, chúng ta dễ dàng cho rằng các phần tử thay đổi trùng nhau và nên được "nén" lại với nhau.

   A       B          C
0  1  [1, 2]     [1, 2]  # Typical to assume these should be zipped [(1, 1), (2, 2)]
1  2  [3, 4]  [3, 4, 5]

Tuy nhiên, giả thiết bị thách thức khi chúng ta nhìn thấy các đối tượng có độ dài khác nhau, chúng ta có nên "zip" không, nếu vậy, chúng ta xử lý phần dư thừa ở một trong các đối tượng như thế nào. HOẶC , có thể chúng ta muốn sản phẩm của tất cả các đối tượng. Điều này sẽ trở nên nhanh chóng, nhưng có thể là những gì được mong muốn.

   A       B          C
0  1  [1, 2]     [1, 2]
1  2  [3, 4]  [3, 4, 5]  # is this [(3, 3), (4, 4), (None, 5)]?

HOẶC LÀ

   A       B          C
0  1  [1, 2]     [1, 2]
1  2  [3, 4]  [3, 4, 5]  # is this [(3, 3), (3, 4), (3, 5), (4, 3), (4, 4), (4, 5)]

Chức năng

Hàm này xử lý một cách duyên dáng ziphoặc productdựa trên một tham số và giả định ziptheo độ dài của đối tượng dài nhất vớizip_longest

from itertools import zip_longest, product

def xplode(df, explode, zipped=True):
    method = zip_longest if zipped else product

    rest = {*df} - {*explode}

    zipped = zip(zip(*map(df.get, rest)), zip(*map(df.get, explode)))
    tups = [tup + exploded
     for tup, pre in zipped
     for exploded in method(*pre)]

    return pd.DataFrame(tups, columns=[*rest, *explode])[[*df]]

Đã nén

xplode(df, ['B', 'C'])

   A    B  C
0  1  1.0  1
1  1  2.0  2
2  2  3.0  3
3  2  4.0  4
4  2  NaN  5

Sản phẩm

xplode(df, ['B', 'C'], zipped=False)

   A  B  C
0  1  1  1
1  1  1  2
2  1  2  1
3  1  2  2
4  2  3  3
5  2  3  4
6  2  3  5
7  2  4  3
8  2  4  4
9  2  4  5

Thiết lập mới

Thay đổi ví dụ một chút

df = pd.DataFrame({
    'A': [1, 2],
    'B': [[1, 2], [3, 4]],
    'C': 'C',
    'D': [[1, 2], [3, 4, 5]],
    'E': [('X', 'Y', 'Z'), ('W',)]
})

df

   A       B  C          D          E
0  1  [1, 2]  C     [1, 2]  (X, Y, Z)
1  2  [3, 4]  C  [3, 4, 5]       (W,)

Đã nén

xplode(df, ['B', 'D', 'E'])

   A    B  C    D     E
0  1  1.0  C  1.0     X
1  1  2.0  C  2.0     Y
2  1  NaN  C  NaN     Z
3  2  3.0  C  3.0     W
4  2  4.0  C  4.0  None
5  2  NaN  C  5.0  None

Sản phẩm

xplode(df, ['B', 'D', 'E'], zipped=False)

    A  B  C  D  E
0   1  1  C  1  X
1   1  1  C  1  Y
2   1  1  C  1  Z
3   1  1  C  2  X
4   1  1  C  2  Y
5   1  1  C  2  Z
6   1  2  C  1  X
7   1  2  C  1  Y
8   1  2  C  1  Z
9   1  2  C  2  X
10  1  2  C  2  Y
11  1  2  C  2  Z
12  2  3  C  3  W
13  2  3  C  4  W
14  2  3  C  5  W
15  2  4  C  3  W
16  2  4  C  4  W
17  2  4  C  5  W

1

Một cái gì đó khá không được khuyến nghị (ít nhất là hoạt động trong trường hợp này):

df=pd.concat([df]*2).sort_index()
it=iter(df['B'].tolist()[0]+df['B'].tolist()[0])
df['B']=df['B'].apply(lambda x:next(it))

concat+ sort_index+ iter+ apply+ next.

Hiện nay:

print(df)

Là:

   A  B
0  1  1
0  1  2
1  2  1
1  2  2

Nếu quan tâm đến chỉ số:

df=df.reset_index(drop=True)

Hiện nay:

print(df)

Là:

   A  B
0  1  1
1  1  2
2  2  1
3  2  2

1
df=pd.DataFrame({'A':[1,2],'B':[[1,2],[1,2]]})

pd.concat([df['A'], pd.DataFrame(df['B'].values.tolist())], axis = 1)\
  .melt(id_vars = 'A', value_name = 'B')\
  .dropna()\
  .drop('variable', axis = 1)

    A   B
0   1   1
1   2   1
2   1   2
3   2   2

Bất kỳ ý kiến ​​về phương pháp này tôi nghĩ ra? hoặc là làm cả concat và tan được coi là quá "tốn kém"?


0
df=pd.DataFrame({'A':[1,2],'B':[[1,2],[1,2]]})

out = pd.concat([df.loc[:,'A'],(df.B.apply(pd.Series))], axis=1, sort=False)

out = out.set_index('A').stack().droplevel(level=1).reset_index().rename(columns={0:"B"})

       A    B
   0    1   1
   1    1   2
   2    2   1
   3    2   2
  • bạn có thể triển khai điều này như một lớp lót, nếu bạn không muốn tạo đối tượng trung gian

0
# Here's the answer to the related question in:
# https://stackoverflow.com/q/56708671/11426125

# initial dataframe
df12=pd.DataFrame({'Date':['2007-12-03','2008-09-07'],'names':
[['Peter','Alex'],['Donald','Stan']]})

# convert dataframe to array for indexing list values (names)
a = np.array(df12.values)  

# create a new, dataframe with dimensions for unnested
b = np.ndarray(shape = (4,2))
df2 = pd.DataFrame(b, columns = ["Date", "names"], dtype = str)

# implement loops to assign date/name values as required
i = range(len(a[0]))
j = range(len(a[0]))
for x in i:
    for y in j:
        df2.iat[2*x+y, 0] = a[x][0]
        df2.iat[2*x+y, 1] = a[x][1][y]

# set Date column as Index
df2.Date=pd.to_datetime(df2.Date)
df2.index=df2.Date
df2.drop('Date',axis=1,inplace =True)

0

Trong trường hợp của tôi với nhiều hơn một cột để phát nổ và với độ dài biến cho các mảng cần được hủy bỏ.

Tôi đã kết thúc việc áp dụng hàm pandas 0,25 mới explodehai lần, sau đó xóa các bản sao đã tạo và nó thực hiện công việc!

df = df.explode('A')
df = df.explode('B')
df = df.drop_duplicates()

0

Tôi có một cách hay khác để giải quyết vấn đề này khi bạn có nhiều hơn một cột để nổ.

df=pd.DataFrame({'A':[1,2],'B':[[1,2],[1,2]], 'C':[[1,2,3],[1,2,3]]})

print(df)
   A       B          C
0  1  [1, 2]  [1, 2, 3]
1  2  [1, 2]  [1, 2, 3]

Tôi muốn làm nổ các cột B và C. Đầu tiên tôi làm nổ B, thứ hai C. Hơn là tôi thả B và C từ df ban đầu. Sau đó, tôi sẽ thực hiện tham gia chỉ mục trên 3 dfs.

explode_b = df.explode('B')['B']
explode_c = df.explode('C')['C']
df = df.drop(['B', 'C'], axis=1)
df = df.join([explode_b, explode_c])
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.