繁体   English   中英

使用多列键重塑熊猫数据框

[英]Reshape a Pandas data frame with multi column key

我有一个熊猫数据框,其中有两列作为唯一值(eng_id,日期)。 我需要将其转换为以下形状,并通过equipment_id唯一值及其测量值创建列。 我怎样才能做到这一点?

From:
     eng_id       date      equipment_id     measurement
        1       2016-01        100                 20
        1       2016-01        200                 46
        1       2016-01        300                 18
        1       2016-04        200                 33
        1       2016-05        200                 27
        2       2016-01        300                 9
        2       2016-01        400                 15   
        2       2016-05        400                 65
        2       2016-05        500                 51
        2       2016-05        600                 16

To:

    ID          100      200      300      400      500     600
1,2016-01       20       46       18        0       0       0
1,2016-04       0        33       0         0       0       0   
1,2016-05       0        27       0         0       0       0 
2,2016-01       0         0       9         15      0       0 
2,2016-05       0         0       0         65      51      16

Concanecate两列,将ID和使用pivot

df['ID'] = df['eng_id'].astype(str) + ',' + df['date']
df = df.pivot(index='ID', columns='equipment_id', values='measurement').fillna(0).astype(int)
print (df)
equipment_id  100  200  300  400  500  600
ID                                        
1,2016-01      20   46   18    0    0    0
1,2016-04       0   33    0    0    0    0
1,2016-05       0   27    0    0    0    0
2,2016-01       0    0    9   15    0    0
2,2016-05       0    0    0   65   51   16

与同类解决方案set_index + unstack

df['ID'] = df['eng_id'].astype(str) + ',' + df['date']
df = df.set_index(['ID', 'equipment_id'])['measurement'].unstack(fill_value=0)
print (df)
equipment_id  100  200  300  400  500  600
ID                                        
1,2016-01      20   46   18    0    0    0
1,2016-04       0   33    0    0    0    0
1,2016-05       0   27    0    0    0    0
2,2016-01       0    0    9   15    0    0
2,2016-05       0    0    0   65   51   16

但是如果需要ID2列:

df = df.set_index(['eng_id', 'date', 'equipment_id'])['measurement'].unstack(fill_value=0)
print (df)
equipment_id    100  200  300  400  500  600
eng_id date                                 
1      2016-01   20   46   18    0    0    0
       2016-04    0   33    0    0    0    0
       2016-05    0   27    0    0    0    0
2      2016-01    0    0    9   15    0    0
       2016-05    0    0    0   65   51   16

对于列,添加reset_index + rename_axis

df = df.set_index(['eng_id', 'date', 'equipment_id'])['measurement'].unstack(fill_value=0)
       .reset_index()
       .rename_axis(None, axis=1)
print (df)
   eng_id     date  100  200  300  400  500  600
0       1  2016-01   20   46   18    0    0    0
1       1  2016-04    0   33    0    0    0    0
2       1  2016-05    0   27    0    0    0    0
3       2  2016-01    0    0    9   15    0    0
4       2  2016-05    0    0    0   65   51   16

但是如果得到:

ValueError:索引包含重复的条目,无法重塑

这意味着您有重复项,并且需要带有一些汇总函数(例如meansum ...)的pivot_table

print (df)
    eng_id     date  equipment_id  measurement
0        1  2016-01           100           20 <-duplicate 1 2016-01 100
1        1  2016-01           100           30 <-duplicate 1 2016-01 100
2        1  2016-01           200           46
3        1  2016-01           300           18
4        1  2016-04           200           33
5        1  2016-05           200           27
6        2  2016-01           300            9
7        2  2016-01           400           15
8        2  2016-05           400           65
9        2  2016-05           500           51
10       2  2016-05           600           16

df['ID'] = df['eng_id'].astype(str) + ',' + df['date']
df = df.pivot_table(index='ID', 
                    columns='equipment_id', 
                    values='measurement', 
                    fill_value=0, 
                    aggfunc='mean')
print (df)
equipment_id  100  200  300  400  500  600
ID                                        
1,2016-01      25   46   18    0    0    0 <= (20+30)/2=25
1,2016-04       0   33    0    0    0    0
1,2016-05       0   27    0    0    0    0
2,2016-01       0    0    9   15    0    0
2,2016-05       0    0    0   65   51   16

或者使用groupby + aggregate function + unstack

df['ID'] = df['eng_id'].astype(str) + ',' + df['date']
df = df.groupby(['ID', 'equipment_id'])['measurement'].mean().unstack(fill_value=0)
print (df)
equipment_id  100  200  300  400  500  600
ID                                        
1,2016-01      25   46   18    0    0    0 <= (20+30)/2=25
1,2016-04       0   33    0    0    0    0
1,2016-05       0   27    0    0    0    0
2,2016-01       0    0    9   15    0    0
2,2016-05       0    0    0   65   51   16

@jezrael的答案涵盖了最惯用的方法。 对我而言,这只是一个探索性练习。 我想分享我的发现。 该技术假定['eng_id', 'date', 'equipment_id']是唯一的。

z = list(zip(df.eng_id.values.tolist(), df.date.values.tolist()))
# i will be the positions I will use to insert into the values array
# u will be the tuples that make up the index
i, u = pd.Series(z).factorize()
idx = pd.MultiIndex.from_tuples(u, names=['eng_id', 'date'])
# j will bet be positions I will use to insert into the values array
# col will be the column labels
j, col = df.equipment_id.factorize()

# Create a place holder dataframe
d = pd.DataFrame(0, idx, col)

# fill the values
d.values[i, j] = df.measurement.values

print(d)

            100  200  300  400  500  600
eng_id date                                 
1      2016-01   20   46   18    0    0    0
       2016-04    0   33    0    0    0    0
       2016-05    0   27    0    0    0    0
2      2016-01    0    0    9   15    0    0
       2016-05    0    0    0   65   51   16

定时
小数据
对于大数据,这看起来可能有所不同,但我尚未对其进行测试。

%%timeit
z = list(zip(df.eng_id.values.tolist(), df.date.values.tolist()))
i, u = pd.Series(z).factorize()
idx = pd.MultiIndex.from_tuples(u, names=['eng_id', 'date'])
j, col = df.equipment_id.factorize()
​
d = pd.DataFrame(0, idx, col)
​
d.values[i, j] = df.measurement.values
1000 loops, best of 3: 885 µs per loop

%timeit df.set_index(['eng_id', 'date', 'equipment_id'])['measurement'].unstack(fill_value=0)
100 loops, best of 3: 1.96 ms per loop

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM