使用Pandas在分类值上移动窗口

时间:2014-07-14 15:28:46

标签: python pandas

我有一个像这样的熊猫系列:

s = pd.Series(["A", "A", "B", "C", "A", "C", "A", "C", "A", "B", "B", "B", "A", "A", "C"])

我希望将每个字母的计数或比例放在大小为4的非重叠窗口中。

我试过这个:

pd.rolling_apply(s, 4, pd.value_counts)

但它不起作用。

ValueError: could not convert string to float: C

是否有任何想法执行此任务?

2 个答案:

答案 0 :(得分:1)

由于您的系列使用RangeIndex,您可以通过除以它们的大小来创建非重叠窗口:

print(s.index // 4)
# => Int64Index([0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3], dtype='int64')

按上述方式分组并使用.value_counts()

s.groupby(s.index // 4).value_counts()

# 0  A    2
#    B    1
#    C    1
# 1  A    2
#    C    2
# 2  B    3
#    A    1
# 3  A    2
#    C    1
# dtype: int64

如果您更喜欢比例而不是计数,请提供.value_counts()参数normalize=True

s.groupby(s.index // 4).value_counts(normalize=True)

# 0  A    0.500000
#    B    0.250000
#    C    0.250000
# 1  A    0.500000
#    C    0.500000
# 2  B    0.750000
#    A    0.250000
# 3  A    0.666667
#    C    0.333333
# dtype: float64

如果你的系列有不同类型的索引,你仍然可以按如下方式生成窗口:

pd.Series(range(len(s))) // 4

# 0     0
# 1     0
# 2     0
# 3     0
# 4     1
# 5     1
# 6     1
# 7     1
# 8     2
# 9     2
# 10    2
# 11    2
# 12    3
# 13    3
# 14    3
# dtype: int64

以下两行中的任何一行都会产生与上面相同的输出:

s.groupby(pd.Series(range(len(s))) // 4).value_counts()
s.groupby(pd.Series(range(len(s))) // 4).value_counts(normalize=True)

答案 1 :(得分:0)

好难题! 我使用for循环来获取所有窗口的字典。然后我构建一个DataFrame,然后我可以使用value_counts()。这是你要的吗?

In [150]: winsize = 4

In [151]: for i in range(len(s)+1-winsize): wd[i] = s[i:i+winsize].tolist()

In [152]: wd
Out[152]: 
{0: ['A', 'A', 'B', 'C'],
 1: ['A', 'B', 'C', 'A'],
 2: ['B', 'C', 'A', 'C'],
 3: ['C', 'A', 'C', 'A'],
 4: ['A', 'C', 'A', 'C'],
 5: ['C', 'A', 'C', 'A'],
 6: ['A', 'C', 'A', 'B'],
 7: ['C', 'A', 'B', 'B'],
 8: ['A', 'B', 'B', 'B'],
 9: ['B', 'B', 'B', 'A'],
 10: ['B', 'B', 'A', 'A'],
 11: ['B', 'A', 'A', 'C']}

In [153]: pd.DataFrame(wd)
Out[153]: 
  0  1  2  3  4  5  6  7  8  9  10 11
0  A  A  B  C  A  C  A  C  A  B  B  B
1  A  B  C  A  C  A  C  A  B  B  B  A
2  B  C  A  C  A  C  A  B  B  B  A  A
3  C  A  C  A  C  A  B  B  B  A  A  C

In [154]: pd.DataFrame(wd).apply(pd.value_counts)
Out[154]: 
   0   1   2   3   4   5   6   7   8   9   10  11
A   2   2   1   2   2   2   2   1   1   1   2   2
B   1   1   1 NaN NaN NaN   1   2   3   3   2   1
C   1   1   2   2   2   2   1   1 NaN NaN NaN   1