Pandas stack / groupby创建一个新的数据帧

时间:2013-09-11 14:01:00

标签: python group-by pandas dataframe

我遇到创建和重新排列数据集的问题。我看着熊猫群体的功能,并认为它可以帮助我做到这一点,但我没有经验可以实现它。 我在下面创建了一个问题示例: 我的df:

     vehicle  color  a  b  c  d  A1  A2  A3  B1  B2  B3  C1  C2  C3  D1  D2  D3
resp                                                                           
1       bike  green  5  4  1  3   3   4   5   3   5   3 NaN NaN NaN NaN NaN NaN
2       walk    red  5  3  3  3   4   5   3   3   5   4 NaN NaN NaN NaN NaN NaN
3        car  green  4  2  3  3   4   3   5   4   5   5 NaN NaN NaN NaN NaN NaN
4        car   blue  4  5  4  4 NaN NaN NaN NaN NaN NaN   5   5   5   3   3   4
5        bus  black  2  4  4  3 NaN NaN NaN   2   3   3   2   2   1 NaN NaN NaN
6        car    red  4  2  3  3   3   4   4 NaN NaN NaN   4   4   4 NaN NaN NaN
7        bus   blue  5  5  2  3   3   3   5   4   3   2 NaN NaN NaN NaN NaN NaN
8       walk    red  3  3  4  3 NaN NaN NaN   5   5   5   5   3   3 NaN NaN NaN
9        car   blue  5  3  4  3   3   3   3 NaN NaN NaN   4   3   4 NaN NaN NaN

数据集包含受访者和问题的答案。我想做的是创建一个新的数据帧,其中resp作为索引,以及来自受访者回答重新排列的数据。 a,b,c,d,车辆和颜色列中的数据是为新数据框中的受访者(希望这是表达它的正确方式)堆叠的。此外,列A到C的值位于列BL_val下的新帧中。只填写大写字母(A1-D3)与小写字母(a,b,c,d)对应的数据。其余为NAN。

我想从这里创建一个新的数据框架,它看起来像:

DS:

     vehicle  color sl  sl_val  BL_val1  BL_val2  BL_val3
resp                                                     
1       bike  green  a       5        3        4        5
1       bike  green  b       4        3        5        3
1       bike  green  c       1      NaN      NaN      NaN
1       bike  green  d       3      NaN      NaN      NaN
2       walk    red  a       5        4        5        3
2       walk    red  b       3        3        5        4
2       walk    red  c       3      NaN      NaN      NaN
2       walk    red  d       3      NaN      NaN      NaN
3        car  green  a       4        4        3        5
3        car  green  b       2        4        5        5
3        car  green  c       3      NaN      NaN      NaN
3        car  green  d       3      NaN      NaN      NaN
4        car   blue  a       4      NaN      NaN      NaN
4        car   blue  b       5      NaN      NaN      NaN
4        car   blue  c       4        5        5        5
4        car   blue  d       4        3        3        4
5        bus  black  a       2      NaN      NaN      NaN
5        bus  black  b       4        2        3        3
5        bus  black  c       4        2        2        1
5        bus  black  d       3      NaN      NaN      NaN
6        car    red  a       4        3        4        4
6        car    red  b       2      NaN      NaN      NaN
6        car    red  c       3        4        4        4
6        car    red  d       3      NaN      NaN      NaN
7        bus   blue  a       5        3        3        5
7        bus   blue  b       5        4        3        2
7        bus   blue  c       2      NaN      NaN      NaN
7        bus   blue  d       3      NaN      NaN      NaN
8       walk    red  a       3      NaN      NaN      NaN
8       walk    red  b       3        5        5        5
8       walk    red  c       4        5        3        3
8       walk    red  d       3      NaN      NaN      NaN
9        car   blue  a       5        3        3        3
9        car   blue  b       3      NaN      NaN      NaN
9        car   blue  c       4        4        3        4
9        car   blue  d     NaN      NaN      NaN      NaN

我真的需要一些帮助,我无法弄明白!!

2 个答案:

答案 0 :(得分:3)

可能有一种更为宽松的方式,但我发现使用groupby制作组,对它们执行显式操作,然后重新组合的模式通常是一种简单的方法来获取我想要。当然,我可以花半个小时想出更优雅的东西,但那时我就没有时间闲逛了......

无论如何,这样的事情怎么样?

df = df.set_index(["resp", "vehicle", "color"])

grouped = df.groupby(lambda x: x[0].lower(), axis=1)

new_grouped = []
for key, group in grouped:
    group.columns = ["sl_val"] + ["BL_val{}".format(i) for i in range(1,4)]
    group["sl"] = key
    new_grouped.append(group)

df2 = pd.concat(new_grouped).reset_index()

df2 = df2.sort(["resp", "vehicle", "color"]).set_index("resp")
df2 = df2[["vehicle", "color", "sl"] + [k for k in df2.columns if "_" in k]]

开始
>>> df = df.set_index(["resp", "vehicle", "color"])
>>> df
                    a  b  c  d  A1  A2  A3  B1  B2  B3  C1  C2  C3  D1  D2  D3
resp vehicle color                                                            
1    bike    green  5  4  1  3   3   4   5   3   5   3 NaN NaN NaN NaN NaN NaN
2    walk    red    5  3  3  3   4   5   3   3   5   4 NaN NaN NaN NaN NaN NaN
3    car     green  4  2  3  3   4   3   5   4   5   5 NaN NaN NaN NaN NaN NaN
4    car     blue   4  5  4  4 NaN NaN NaN NaN NaN NaN   5   5   5   3   3   4
5    bus     black  2  4  4  3 NaN NaN NaN   2   3   3   2   2   1 NaN NaN NaN
6    car     red    4  2  3  3   3   4   4 NaN NaN NaN   4   4   4 NaN NaN NaN
7    bus     blue   5  5  2  3   3   3   5   4   3   2 NaN NaN NaN NaN NaN NaN
8    walk    red    3  3  4  3 NaN NaN NaN   5   5   5   5   3   3 NaN NaN NaN
9    car     blue   5  3  4  3   3   3   3 NaN NaN NaN   4   3   4 NaN NaN NaN

我们可以用小写的起始字母分组:

>>> grouped = df.groupby(lambda x: x[0].lower(), axis=1)

制作一组看似如下的组:

>>> next(iter(grouped))
('a',                     a  A1  A2  A3
resp vehicle color               
1    bike    green  5   3   4   5
2    walk    red    5   4   5   3
3    car     green  4   4   3   5
4    car     blue   4 NaN NaN NaN
5    bus     black  2 NaN NaN NaN
6    car     red    4   3   4   4
7    bus     blue   5   3   3   5
8    walk    red    3 NaN NaN NaN
9    car     blue   5   3   3   3)

然后我们只需更改名称,添加"sl"列,然后使用pd.concat重新组合它们。最后一位只是匹配您想要的订单。

最终结果:

>>> df2
     vehicle  color sl  sl_val  BL_val1  BL_val2  BL_val3
resp                                                     
1       bike  green  a       5        3        4        5
1       bike  green  b       4        3        5        3
1       bike  green  c       1      NaN      NaN      NaN
1       bike  green  d       3      NaN      NaN      NaN
2       walk    red  a       5        4        5        3
2       walk    red  b       3        3        5        4
2       walk    red  c       3      NaN      NaN      NaN
2       walk    red  d       3      NaN      NaN      NaN
3        car  green  a       4        4        3        5
3        car  green  b       2        4        5        5
3        car  green  c       3      NaN      NaN      NaN
3        car  green  d       3      NaN      NaN      NaN
4        car   blue  a       4      NaN      NaN      NaN
4        car   blue  b       5      NaN      NaN      NaN
4        car   blue  c       4        5        5        5
4        car   blue  d       4        3        3        4
5        bus  black  a       2      NaN      NaN      NaN
5        bus  black  b       4        2        3        3
5        bus  black  c       4        2        2        1
5        bus  black  d       3      NaN      NaN      NaN
6        car    red  a       4        3        4        4
6        car    red  b       2      NaN      NaN      NaN
6        car    red  c       3        4        4        4
6        car    red  d       3      NaN      NaN      NaN
7        bus   blue  a       5        3        3        5
7        bus   blue  b       5        4        3        2
7        bus   blue  c       2      NaN      NaN      NaN
7        bus   blue  d       3      NaN      NaN      NaN
8       walk    red  a       3      NaN      NaN      NaN
8       walk    red  b       3        5        5        5
8       walk    red  c       4        5        3        3
8       walk    red  d       3      NaN      NaN      NaN
9        car   blue  a       5        3        3        3
9        car   blue  b       3      NaN      NaN      NaN
9        car   blue  c       4        4        3        4
9        car   blue  d       3      NaN      NaN      NaN

答案 1 :(得分:3)

一种天真的方式是写一个辅助函数来提取相关的subDataFrames:

In [11]: def get_letter(df, letter):
             res = df.loc[:, ['vehicle', 'color', letter] + [letter.upper() + str(i) for i in xrange(1, 4)]]
             res.columns = ['vehicle', 'color', 'sl_val', 'BL_val1', 'BL_val2', 'BL_val3']
             res['sl'] = letter
             return res

In [12]: get_letter(df, 'a')
Out[12]: 
     vehicle  color  sl_val  BL_val1  BL_val2  BL_val3 sl
resp                                                     
1       bike  green       5        3        4        5  a
2       walk    red       5        4        5        3  a
3        car  green       4        4        3        5  a
4        car   blue       4      NaN      NaN      NaN  a
5        bus  black       2      NaN      NaN      NaN  a
6        car    red       4        3        4        4  a
7        bus   blue       5        3        3        5  a
8       walk    red       3      NaN      NaN      NaN  a
9        car   blue       5        3        3        3  a

然后将这些结果得到你得到的结果(可能有一个排序):

In [13]: pd.concat(get_letter(df, letter) for letter in 'abcd')

In [14]: pd.concat(get_letter(df, letter) for letter in 'abcd').sort()