将多个pandas数据帧合并到一个数据帧中,并将内容连接为列表

时间:2017-08-23 11:26:23

标签: python pandas dataframe

我有一个包含未知数量的pandas数据帧的字典。每个数据框都包含一组始终存在的列(user_id)和一组可能存在或可能不存在的列。所有数据帧都具有相同的行数和顺序。每个单元格的内容都是一个列表(对于我感兴趣的列)。

简化示例:

df['first']     = pd.DataFrame(  {'user_ID': [1, 2, 3],
                        'col1': [[1], [2,3], [3]],
                        'col2': [[3], [3], [3,1]],
                        'col3': [[], [1,2,3], [3,1]]} )

df['second']    = pd.DataFrame(  {'user_ID': [1, 2, 3],
                        'col1': [[1, 2], [3], [3]],
                        'col3': [[1], [2,3], [3]],
                        'col4': [[3], [3], [3,1]] })

df['last']      = pd.DataFrame(  {'user_ID': [1, 2, 3],
                        'col1': [[1], [2,3], [3]],
                        'col2': [[3], [3], [3,1]],
                        'col5': [[], [1,2,3], [3,1]]} )

他们看起来像:

     col1    col2       col3  user_ID
0     [1]     [3]         []        1
1  [2, 3]     [3]  [1, 2, 3]        2
2     [3]  [3, 1]     [3, 1]        3

     col1    col3    col4  user_ID
0  [1, 2]     [1]     [3]        1
1     [3]  [2, 3]     [3]        2
2     [3]     [3]  [3, 1]        3

     col1    col2       col5  user_ID
0     [1]     [3]         []        1
1  [2, 3]     [3]  [1, 2, 3]        2
2     [3]  [3, 1]     [3, 1]        3

如何将所有这些数据框合并到一个数据框中,其中所有非user_ID的列都已合并,因此内容会附加到列表中?

结果应如下(每个列表中元素的顺序无关紧要):

              col1          col2             col3    col4       col5   user_ID
0     [1, 1, 2, 1]        [3, 3]              [1]     [3]         []         1
1  [2, 3, 3, 2, 3]        [3, 3]  [1, 2, 3, 2, 3]     [2]  [1, 2, 3]         2
2        [3, 3, 3]  [3, 1, 3, 1]        [3, 1, 3]  [3, 1]     [3, 1]         3

我设法连接数据帧,但我仍然需要合并生成的列。

for dfName in ['first', 'second', 'last']:
    df[dfName] = df[dfName].drop(['user_ID'], axis=1)

merged = pd.concat(df, axis=1, keys=['first', 'second', 'last'])
print(merged)

输出:

    first                     second                    last          \
     col1    col2       col3    col1    col3    col4    col1    col2
0     [1]     [3]         []  [1, 2]     [1]     [3]     [1]     [3]
1  [2, 3]     [3]  [1, 2, 3]     [3]  [2, 3]     [3]  [2, 3]     [3]
2     [3]  [3, 1]     [3, 1]     [3]     [3]  [3, 1]     [3]  [3, 1]


        col5
0         []
1  [1, 2, 3]
2     [3, 1]

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

这有点牵扯,但你需要for item in soup.find_all('p', id=re.compile('^test')): 。首先,使用df.groupby并加入它们。然后使用pd.concat替换NaN,最后使用groupby和sum。

df.applymap

由于Maarten Fabré,效率略有提高。

如果您拥有未知数量的数据框,可以将它们放在In [673]: pd.concat([df1, df2, df3], 0)\ .applymap(lambda x: [] if x != x else x)\ .groupby('user_ID', as_index=False).sum() Out[673]: user_ID col1 col2 col3 col4 col5 0 1 [1, 1, 2, 1] [3, 3] [1] [3] [] 1 2 [2, 3, 3, 2, 3] [3, 3] [1, 2, 3, 2, 3] [3] [1, 2, 3] 2 3 [3, 3, 3] [3, 1, 3, 1] [3, 1, 3] [3, 1] [3, 1] list中,并将其传递给dict

pd.concat

答案 1 :(得分:1)

如果不是df.groupby('user_ID').sum()值,则可以使用nan,这会导致所有列与col1分开。

要解决这个问题,你可以使用这种相当丑陋的方法

pd.concat((df0, df1, df2)).fillna(-1).applymap(lambda x: x if x != -1 else []).groupby('user_ID').sum()

我不得不诉诸fillna(-1).applymap(...),因为您似乎无法将[]直接分配给某个项目。如果有人有更好的建议,请告诉我

修改

使用@ COLDSPEED将NaNNaN进行比较的技巧

pd.concat((df0, df1, df2)).applymap(lambda x: x if x == x else []).groupby('user_ID').sum()

更轻松

如果您想将user_ID作为列,n而不是索引,只需添加.reset_index()