用重复模式填充python pandas数据框中的缺失行

时间:2019-07-18 12:15:17

标签: python-3.x pandas dataframe

我正在尝试像这样修复pandas DataFrame中缺少的行:

import pandas as pd

df = pd.DataFrame([[1, 1.2, 3.4], [2, 4.5, 6.7], [3, 1.3, 2.5], [4, 5.6, 7.3],
               [1, 3.4, 5.8], [2, 5.7, 8.9], [4, 2.4, 2.6], [1, 6.7, 8.4],
               [3, 6.9, 4.2], [4, 4.2, 1.2]], columns = ['#', 'foo', 'bar'])

上面的代码给了我这样的熊猫数据框:

Out[10]: 
   #  foo  bar
0  1  1.2  3.4
1  2  4.5  6.7
2  3  1.3  2.5
3  4  5.6  7.3
4  1  3.4  5.8
5  2  5.7  8.9
6  4  2.4  2.6
7  1  6.7  8.4
8  3  6.9  4.2
9  4  4.2  1.2

您可能已经注意到,'#'列中的值以1, 2, 3, 4, 1, 2, 3, 4 ...的形式重复出现,但是缺少一些值(在这种情况下,第6行和{{ 1}}在第8行之前)。 我的问题是:根据3列的重复模式,大熊猫中是否有任何内置方法(函数)来填充此数据框中的缺失行?填充行可以是2,也可以是填充行之前和/或之后的值的内插\外推\平均值。换句话说,我想要的是这样的:

'#'

我尝试将NaN列设置为数据框的索引,并使用常规模式对其重新索引,而不会丢失值。但是问题是Out[16]: # foo bar 0 1 1.2 3.4 1 2 4.5 6.7 2 3 1.3 2.5 3 4 5.6 7.3 4 1 3.4 5.8 5 2 5.7 8.9 6 3 NaN NaN 7 4 2.4 2.6 8 1 6.7 8.4 9 2 NaN NaN 10 3 6.9 4.2 11 4 4.2 1.2 不适用于重复的值。我知道我总是可以通过在行与行之间的循环中进行迭代来解决问题的,这是传统的方式,但是如果使用大数据,这恐怕会很耗时。

如果有人可以给我提示,我将不胜感激。

3 个答案:

答案 0 :(得分:3)

您需要以某种方式创建组-这里使用值差异#并与Series.le比较>1,然后将GroupBy.applySeries.reindex比较:

df1 = (df.groupby(df['#'].diff().lt(1).cumsum())
         .apply(lambda x: x.set_index('#').reindex(range(1, 5)))
         .reset_index(level=0, drop=True)
         .reset_index())

print (df1)
    #  foo  bar
0   1  1.2  3.4
1   2  4.5  6.7
2   3  1.3  2.5
3   4  5.6  7.3
4   1  3.4  5.8
5   2  5.7  8.9
6   3  NaN  NaN
7   4  2.4  2.6
8   1  6.7  8.4
9   2  NaN  NaN
10  3  6.9  4.2
11  4  4.2  1.2

另一个想法是创建MultiIndex并通过unstackstack重塑形状:

df = (df.set_index(['#', df['#'].diff().lt(1).cumsum()])
       .unstack()
       .reindex(np.arange(4)+1)
       .stack(dropna=False)
       .sort_index(level=1)
       .reset_index(level=1, drop=True)
       .reset_index())
print (df)
    #  foo  bar
0   1  1.2  3.4
1   2  4.5  6.7
2   3  1.3  2.5
3   4  5.6  7.3
4   1  3.4  5.8
5   2  5.7  8.9
6   3  NaN  NaN
7   4  2.4  2.6
8   1  6.7  8.4
9   2  NaN  NaN
10  3  6.9  4.2
11  4  4.2  1.2

答案 1 :(得分:3)

我们可以用1,2,3,4eq标记cumsum的每组。

然后我们groupby在这些组上使用reindex,最后concat将它们重新组合在一起。

s = df['#'].eq(4).shift().cumsum().bfill()

pd.concat(
    [d.set_index('#').reindex(np.arange(4)+1) for _, d in df.groupby(s)]
).reset_index()

输出

    #  foo  bar
0   1  1.2  3.4
1   2  4.5  6.7
2   3  1.3  2.5
3   4  5.6  7.3
4   1  3.4  5.8
5   2  5.7  8.9
6   3  NaN  NaN
7   4  2.4  2.6
8   1  6.7  8.4
9   2  NaN  NaN
10  3  6.9  4.2
11  4  4.2  1.2

注意:如果您在4列中缺少#作为值,则此方法将失败。

答案 2 :(得分:1)

这与@jezrael的reindexsort_index相似:

df['rep'] = df['#'].diff().le(0).cumsum()

(df.set_index(['rep','#'])
   .unstack('#')
   .stack('#', dropna=False)
   .reset_index('#')
   .reset_index(drop=True)
)

输出:

    #  foo  bar
0   1  1.2  3.4
1   2  4.5  6.7
2   3  1.3  2.5
3   4  5.6  7.3
4   1  3.4  5.8
5   2  5.7  8.9
6   3  NaN  NaN
7   4  2.4  2.6
8   1  6.7  8.4
9   2  NaN  NaN
10  3  6.9  4.2
11  4  4.2  1.2