python pandas 传输dataframe的格式

python pandas Transfer the format of the dataframe

我有一个名为 df 的数据框,如下所示:(没有重复的 df 行)

a_id           b_id

111111         18
111111         17
222222         18
333333         14
444444         13 
555555         18
555555         24
222222         13
222222         17
333333         17

我想像这样将其转换为数据框 df_2:

a_one     a_two      b_list   number_of_b  
222222    444444     13       1
111111    222222     17,18    2
111111    333333     17       1
111111    222222     17       1
222222    333333     17       1
111111    555555     18       1
222222    555555     18       1   

如果 a_id 共享相同的 b_id,他们将在 df_2 上成为一对;

df_2的b_list对应的是b_id;

number_of_b是b_list的长度

我有一个解决办法: 首先,使 a_id 的组合具有相同的 b_id:

from itertools import combinations
df = df.groupby("b_id").apply(lambda x: list(combinations(x["a_id"], 2))).apply(pd.Series).stack()

df 现在是:

 b_id
13    0    (444444, 222222)
17    0    (111111, 222222)
      1    (111111, 333333)
      2    (222222, 333333)
18    0    (111111, 222222)
      1    (111111, 555555)
      2    (222222, 555555)

然后拆分Series,重新设置index,concat出现b_id:

df = df.apply(pd.Series).reset_index().groupby([0,1])["b_id"].apply(lambda x:x.values).reset_index()

现在我们得到:

        0       1      b_id
0  111111  222222  [17, 18]
1  111111  333333      [17]
2  111111  555555      [18]
3  222222  333333      [17]
4  222222  555555      [18]
5  444444  222222      [13]

这几乎就是您所需要的。 对于确切的结果:

df.columns = ["a_one", "a_two", "b_list"]
df["number_of_b"] = df.b_list.apply(len)

最终结果:

    a_one   a_two    b_list  number_of_b
0  111111  222222  [17, 18]            2
1  111111  333333      [17]            1
2  111111  555555      [18]            1
3  222222  333333      [17]            1
4  222222  555555      [18]            1
5  444444  222222      [13]            1

为清楚起见,完整代码:

from itertools import combinations
df = df.groupby("b_id").apply(lambda x: list(combinations(x["a_id"], 2))).apply(pd.Series).stack()
df = df.apply(pd.Series).reset_index().groupby([0,1])["b_id"].apply(lambda x:x.values).reset_index()
df.columns = ["a_one", "a_two", "b_list"]
df["number_of_b"] = df.b_list.apply(len)

这不是那么花哨。期待更好的解决方案!

使用一系列 groupby 和转换的链式操作:

from itertools import combinations
df2 = (
       df.groupby('b_id')['a_id']
       .apply(lambda x: list(combinations(x.values,2)))
       .apply(pd.Series).stack()
       .reset_index(0)
       .groupby(0).apply(lambda x: [len(x), x.b_id.astype(str).tolist()])
       .apply(pd.Series)
       .rename(columns={0:'b_list', 1:'number_of_b'})
       .pipe(lambda x: x.reset_index(drop=True)
             .join(x.reset_index()[0].apply(pd.Series)))
       .rename(columns={0:'a_one', 1:'a_two'})
       .assign(number_of_b=lambda x: x.number_of_b.str.join(','))
    )[['a_one','a_two','b_list','number_of_b']]



df2
Out[123]: 
    a_one   a_two  b_list number_of_b
0  111111  222222       2       17,18
1  111111  333333       1          17
2  111111  555555       1          18
3  222222  333333       1          17
4  222222  555555       1          18
5  444444  222222       1          13