在熊猫的分组数据中插入值为零的缺失记录

时间:2019-05-06 13:41:05

标签: python pandas

我有一个数据框df

import pandas as pd
s = {'id': [243,243, 243, 243, 443,443,443, 332,334,332,332, 333],
 'col':[1,1,1,1,1,1,1,2,2,2,2,2],
 'st': [1,3,5,9,12, 18,23, 1,2,4,8,14],
 'value':[2.4, 3.8, 3.7, 5.6, 1.2, 0.2, 2.1, 2.0, 2.5, 3.4, 1.2, 2.4]}
df = pd.DataFrame(s)

它看起来像:

id      col  st  value
0   243    1   1    2.4
1   243    1   3    3.8
2   243    1   5    3.7
3   243    1   9    5.6
4   443    1  12    1.2
5   443    1  18    0.2
6   443    1  23    2.1
7   332    2   1    2.0
8   334    2   2    2.5
9   332    2   4    3.4
10  332    2   8    1.2
11  333    2  14    2.4

数据有两组col 1和2(在实际数据中有许多组)。我想在st列的基础上包括缺少的记录。并且值必须保持为0。

我的输出必须像

id  col  st  value
243    1   1    2.4
0      1   2     0
243    1   3    3.8
0      1   4     0
243    1   5    3.7

以此类推

332    2   1    2.0
334    2   2    2.5
0      2   3     0
332    2   4    3.4
0      2   5     0
0      2   6     0
0      2   7     0
332    2   8    1.2

如何在熊猫中做到这一点?

3 个答案:

答案 0 :(得分:2)

每个组分别与DataFrame.reindexrange使用GroupBy.apply

df = (df.set_index('st')
        .groupby('col')['id','value']
        .apply(lambda x: x.reindex(range(x.index.min(), x.index.max() + 1), fill_value=0))
        .reset_index()
       )

print (df)
    col  st   id  value
0     1   1  243    2.4
1     1   2    0    0.0
2     1   3  243    3.8
3     1   4    0    0.0
4     1   5  243    3.7
5     1   6    0    0.0
6     1   7    0    0.0
7     1   8    0    0.0
8     1   9  243    5.6
9     1  10    0    0.0
10    1  11    0    0.0
11    1  12  443    1.2
12    1  13    0    0.0
13    1  14    0    0.0
14    1  15    0    0.0
15    1  16    0    0.0
16    1  17    0    0.0
17    1  18  443    0.2
18    1  19    0    0.0
19    1  20    0    0.0
20    1  21    0    0.0
21    1  22    0    0.0
22    1  23  443    2.1
23    2   1  332    2.0
24    2   2  334    2.5
25    2   3    0    0.0
26    2   4  332    3.4
27    2   5    0    0.0
28    2   6    0    0.0
29    2   7    0    0.0
30    2   8  332    1.2
31    2   9    0    0.0
32    2  10    0    0.0
33    2  11    0    0.0
34    2  12    0    0.0
35    2  13    0    0.0
36    2  14  333    2.4

答案 1 :(得分:1)

使用unnesting的方法,首先使用range + groupby创建agg,然后只需将其爆炸并merge

s=df.groupby(['id','col']).st.agg(['min','max'])
s['st']=[ list(range(x,y+1)) for x , y in zip(s['min'],s['max'])]
newdf=unnesting(s.drop(['min','max'],1).reset_index(),['st']).merge(df,how='left').fillna(0)

def unnesting(df, explode):
    idx = df.index.repeat(df[explode[0]].str.len())
    df1 = pd.concat([
        pd.DataFrame({x: np.concatenate(df[x].values)}) for x in explode], axis=1)
    df1.index = idx

    return df1.join(df.drop(explode, 1), how='left')

答案 2 :(得分:1)

制作一个数据框然后合并。

您可以利用merge自动合并到通用命名列的事实。因此,我们的目标是创建一个仅包含所需列和所需值的数据框。

  • 我们需要的列'col''st'
  • 我们需要的值'col'中的每个唯一值以及其各自组中从最小值到最大值的所有整数值。请注意,我只是抓住了最大值,并假设最小值为1
  • 合并:我确保使用'left'合并来保留我刚刚创建的所有漂亮值。

m = pd.DataFrame(
    [(i, j) for i, J in df.groupby('col').st.max().items()
     for j in range(1, J + 1)],
    columns=['col', 'st']
)

m.merge(df, 'left').fillna(0)

输出

    col  st     id  value
0     1   1  243.0    2.4
1     1   2    0.0    0.0
2     1   3  243.0    3.8
3     1   4    0.0    0.0
4     1   5  243.0    3.7
5     1   6    0.0    0.0
6     1   7    0.0    0.0
7     1   8    0.0    0.0
8     1   9  243.0    5.6
9     1  10    0.0    0.0
10    1  11    0.0    0.0
11    1  12  443.0    1.2
12    1  13    0.0    0.0
13    1  14    0.0    0.0
14    1  15    0.0    0.0
           ...
22    1  23  443.0    2.1
23    2   1  332.0    2.0
24    2   2  334.0    2.5
25    2   3    0.0    0.0
26    2   4  332.0    3.4
27    2   5    0.0    0.0
28    2   6    0.0    0.0
29    2   7    0.0    0.0
30    2   8  332.0    1.2
31    2   9    0.0    0.0
32    2  10    0.0    0.0
33    2  11    0.0    0.0
34    2  12    0.0    0.0
35    2  13    0.0    0.0
36    2  14  333.0    2.4

我们可以更加谨慎一些,并使用agg来获取minmax,然后在调用时使用参数dtype来保存downcast='infer'fillna

m = pd.DataFrame(
    [(i, j) for i, Mn, Mx in df.groupby('col').st.agg(['min', 'max']).itertuples()
     for j in range(Mn, Mx + 1)],
    columns=['col', 'st']
)

m.merge(df, 'left').fillna(0, downcast='infer')

输出

    col  st   id  value
0     1   1  243    2.4
1     1   2    0    0.0
2     1   3  243    3.8
3     1   4    0    0.0
4     1   5  243    3.7
5     1   6    0    0.0
6     1   7    0    0.0
7     1   8    0    0.0
8     1   9  243    5.6
9     1  10    0    0.0
10    1  11    0    0.0
11    1  12  443    1.2
12    1  13    0    0.0
13    1  14    0    0.0
14    1  15    0    0.0
           ...
22    1  23  443    2.1
23    2   1  332    2.0
24    2   2  334    2.5
25    2   3    0    0.0
26    2   4  332    3.4
27    2   5    0    0.0
28    2   6    0    0.0
29    2   7    0    0.0
30    2   8  332    1.2
31    2   9    0    0.0
32    2  10    0    0.0
33    2  11    0    0.0
34    2  12    0    0.0
35    2  13    0    0.0
36    2  14  333    2.4