Pandas Dataframe:将共享同一列值的多行转移/合并为一行

时间:2018-11-30 19:01:45

标签: python pandas

很抱歉,可能与标题混淆。我将用以下代码和图片更好地描述我的问题。

现在我有一个包含多列的数据框。前两列是按“ Route”和“ ID”排序的(对于格式,很抱歉,此处的所有行的“ Route”值为“ 100”,“ ID”从1到3)。

df1.head(9)
  Route ID  Year    Vol Truck_Vol   Truck_%
0   100 1   2017.0  7016    635.0   9.1
1   100 1   2014.0  6835    NaN NaN
2   100 1   2011.0  5959    352.0   5.9
3   100 2   2018.0  15828   NaN NaN
4   100 2   2015.0  13114   2964.0  22.6
5   100 2   2009.0  11844   1280.0  10.8
6   100 3   2016.0  15434   NaN NaN
7   100 3   2013.0  18699   2015.0  10.8
8   100 3   2010.0  15903   NaN NaN

我想拥有的是

 Route  ID  Year    Vol1    Truck_Vol1  Truck_%1    Year2   Vol2    Truck_Vol2  Truck_%2    Year3   Vol3    Truck_Vol3  Truck_%3
0   100 1   2017    7016    635.0   9.1 2014    6835    NaN NaN 2011    5959    352.0   5.9
1   100 2   2018    15828   NaN NaN 2015    13114   2964.0  22.6    2009    11844   1280.0  10.8
2   100 3   2016    15434   NaN NaN 2013    18699   2015.0  10.8    2010    15903   NaN NaN

再次,很抱歉格式混乱。让我尝试一个简化版本。

输入:

  Route ID  Year    Vol T_%
0   100 1   2017    100 1.0
1   100 1   2014    200 NaN
2   100 1   2011    300 2.0
3   100 2   2018    400 NaN
4   100 2   2015    500 3.0
5   100 2   2009    600 4.0

所需的输出:

Route   ID  Year    Vol T_% Year.1  Vol.1   T_%.1   Year.2  Vol.2   T_%.2
0   100 1   2017    100 1.0 2014    200     NaN     2011    300      2
1   100 2   2018    400 NaN 2015    500     3.0     2009    600      4

所以基本上只需移动图片中显示的单元格

Input

Output

我被困在这里。新生成的列的名称无关紧要。

对于此当前数据框,每个“组”都有三行,如代码中所示。如果答案可以容纳每组任意数量的行,那就太好了。

感谢您的宝贵时间。

2 个答案:

答案 0 :(得分:5)

带有groupby + cumcount + set_index + unstack

df1 = df.assign(cid = df.groupby(['Route', 'ID']).cumcount()).set_index(['Route', 'ID', 'cid']).unstack(-1).sort_index(1,1)
df1.columns = [f'{x}{y}' for x,y in df1.columns]
df1 = df1.reset_index()

输出df1

   Route  ID  T_%0  Vol0  Year0  T_%1  Vol1  Year1  T_%2  Vol2  Year2
0    100   1   1.0   100   2017   NaN   200   2014   2.0   300   2011
1    100   2   NaN   400   2018   3.0   500   2015   4.0   600   2009

答案 1 :(得分:4)

melt + pivot_table

v = df.melt(id_vars=['Route', 'ID'])
v['variable'] += v.groupby(['Route', 'ID', 'variable']).cumcount().astype(str)

res = v.pivot_table(index=['Route', 'ID'], columns='variable', values='value')

variable  T_% 0  T_% 1  T_% 2  Vol 0  Vol 1  Vol 2  Year 0  Year 1  Year 2
Route ID
100   1     1.0    NaN    2.0  100.0  200.0  300.0  2017.0  2014.0  2011.0
      2     NaN    3.0    4.0  400.0  500.0  600.0  2018.0  2015.0  2009.0

如果要对这些内容进行排序:

c = res.columns.str.extract(r'(\d+)')[0].values.astype(int)
res.iloc[:,np.argsort(c)]

variable  T_%0   Vol0   Year0  T_%1   Vol1   Year1  T_%2   Vol2   Year2
Route ID
100   1    1.0  100.0  2017.0   NaN  200.0  2014.0   2.0  300.0  2011.0
      2    NaN  400.0  2018.0   3.0  500.0  2015.0   4.0  600.0  2009.0

您问我为什么使用cumcount。为了解释,这是v的上方样子:

    Route  ID variable   value
0     100   1     Year  2017.0
1     100   1     Year  2014.0
2     100   1     Year  2011.0
3     100   2     Year  2018.0
4     100   2     Year  2015.0
5     100   2     Year  2009.0
6     100   1      Vol   100.0
7     100   1      Vol   200.0
8     100   1      Vol   300.0
9     100   2      Vol   400.0
10    100   2      Vol   500.0
11    100   2      Vol   600.0
12    100   1      T_%     1.0
13    100   1      T_%     NaN
14    100   1      T_%     2.0
15    100   2      T_%     NaN
16    100   2      T_%     3.0
17    100   2      T_%     4.0

如果我在此DataFrame上使用pivot_table,则最终会得到如下结果:

variable  T_%    Vol    Year
Route ID
100   1   1.5  200.0  2014.0
      2   3.5  500.0  2014.0

很显然,您正在此处丢失数据。 cumcount是解决方案,因为它将variable系列变成这样:

    Route  ID variable   value
0     100   1    Year0  2017.0
1     100   1    Year1  2014.0
2     100   1    Year2  2011.0
3     100   2    Year0  2018.0
4     100   2    Year1  2015.0
5     100   2    Year2  2009.0
6     100   1     Vol0   100.0
7     100   1     Vol1   200.0
8     100   1     Vol2   300.0
9     100   2     Vol0   400.0
10    100   2     Vol1   500.0
11    100   2     Vol2   600.0
12    100   1     T_%0     1.0
13    100   1     T_%1     NaN
14    100   1     T_%2     2.0
15    100   2     T_%0     NaN
16    100   2     T_%1     3.0
17    100   2     T_%2     4.0

其中每个唯一的RouteID都有重复的元素计数。