运行 连续相同值的总数
Running total of consecutive identical values
如何在 pandas 系列中得到 运行 个连续的 1?
例如,s = pd.Series([5, 1, 4, 1, 1, 2, 3, 1, 1, 1, 4])
。我想获得pd.Series([0, 1, 0, 1, 2, 0, 0, 1, 2, 3, 0])
.
(Pandas 0.18.0)
不是最漂亮的方法(也可能不是最佳的),但以下方法可以完成工作(并且比其他循环答案快 4.5 倍):
s = pd.Series([5, 1, 4, 1, 1, 2, 3, 1, 1, 1, 4])
def consecutive_n(s, n=1):
a = s[s==n].cumsum()[s.index].fillna(0) / n
b = a[a.diff() > 1]
c = (b.rank() - b)[s.index].fillna(0).cumsum()
return (a + c).apply(lambda x: np.where(x<0, 0, x)).astype(int)
>>> consecutive_n(s, n=1)
0 0
1 1
2 0
3 1
4 2
5 0
6 0
7 1
8 2
9 3
10 0
dtype: int64
中间值的一些解释:
a
: 1 在整个系列中第 n 次出现。
c
:当 1(或 n)之间出现不同的数字时,必须将 a
添加到 "reset" 的出现次数。
return 值:应用 lambda 忽略形成 a + c
.
的负数
编辑:
稍微更改了代码,使其适用于任何正整数。示例:
>>> t = pd.Series([1, 2, 3, 1, 4, 2, 2, 3, 2, 2, 2, 1])
>>> consecutive_n(t, 2)
0 0
1 1
2 0
3 0
4 0
5 1
6 2
7 0
8 1
9 2
10 3
11 0
dtype: int64
你可以试试groupby
with cumcount
comparing s1 != 1
with cumsum
:
print s1.groupby((s1 != 1).cumsum()).cumcount()
0 0
1 1
2 0
3 1
4 2
5 0
6 0
7 1
8 2
9 3
10 0
dtype: int64
更好的解释:
df = pd.DataFrame(s1, columns=['orig'])
df['not1'] = s1 != 1
df['cumsum'] = (s1 != 1).cumsum()
df['cumcount'] = s1.groupby((s1 != 1).cumsum()).cumcount()
#s1.groupby((s1 != 1).cumsum()).cumcount() is same as:
df['cumcount1'] = df.groupby('cumsum')['orig'].cumcount()
print df
orig not1 cumsum cumcount cumcount1
0 5 True 1 0 0
1 1 False 1 1 1
2 3 True 2 0 0
3 4 True 3 0 0
4 1 False 3 1 1
5 1 False 3 2 2
6 2 True 4 0 0
7 3 True 5 0 0
8 1 False 5 1 1
9 1 False 5 2 2
10 1 False 5 3 3
11 4 True 6 0 0
或者:
print (s1 == 1) * (s1.groupby((s1 != s1.shift()).cumsum()).cumcount() + 1)
0 0
1 1
2 0
3 1
4 2
5 0
6 0
7 1
8 2
9 3
10 0
dtype: int64
解释:
df = pd.DataFrame(s1, columns=['orig'])
df['compare_shift'] = s1 != s1.shift()
df['cumsum'] = (s1 != s1.shift()).cumsum()
df['cumcount'] = s1.groupby((s1 != s1.shift()).cumsum()).cumcount() + 1
df['cumcount1'] = df.groupby('cumsum')['orig'].cumcount() + 1
df['is1'] = (s1 == 1)
#True in converted to 1, False to 0
df['fin'] = (s1 == 1) * (s1.groupby((s1 != s1.shift()).cumsum()).cumcount() + 1)
print df
orig compare_shift cumsum cumcount cumcount1 is1 fin
0 5 True 1 1 1 False 0
1 1 True 2 1 1 True 1
2 3 True 3 1 1 False 0
3 4 True 4 1 1 False 0
4 1 True 5 1 1 True 1
5 1 False 5 2 2 True 2
6 2 True 6 1 1 False 0
7 3 True 7 1 1 False 0
8 1 True 8 1 1 True 1
9 1 False 8 2 2 True 2
10 1 False 8 3 3 True 3
11 4 True 9 1 1 False 0
如何在 pandas 系列中得到 运行 个连续的 1?
例如,s = pd.Series([5, 1, 4, 1, 1, 2, 3, 1, 1, 1, 4])
。我想获得pd.Series([0, 1, 0, 1, 2, 0, 0, 1, 2, 3, 0])
.
(Pandas 0.18.0)
不是最漂亮的方法(也可能不是最佳的),但以下方法可以完成工作(并且比其他循环答案快 4.5 倍):
s = pd.Series([5, 1, 4, 1, 1, 2, 3, 1, 1, 1, 4])
def consecutive_n(s, n=1):
a = s[s==n].cumsum()[s.index].fillna(0) / n
b = a[a.diff() > 1]
c = (b.rank() - b)[s.index].fillna(0).cumsum()
return (a + c).apply(lambda x: np.where(x<0, 0, x)).astype(int)
>>> consecutive_n(s, n=1)
0 0
1 1
2 0
3 1
4 2
5 0
6 0
7 1
8 2
9 3
10 0
dtype: int64
中间值的一些解释:
a
: 1 在整个系列中第 n 次出现。
c
:当 1(或 n)之间出现不同的数字时,必须将 a
添加到 "reset" 的出现次数。
return 值:应用 lambda 忽略形成 a + c
.
编辑: 稍微更改了代码,使其适用于任何正整数。示例:
>>> t = pd.Series([1, 2, 3, 1, 4, 2, 2, 3, 2, 2, 2, 1])
>>> consecutive_n(t, 2)
0 0
1 1
2 0
3 0
4 0
5 1
6 2
7 0
8 1
9 2
10 3
11 0
dtype: int64
你可以试试groupby
with cumcount
comparing s1 != 1
with cumsum
:
print s1.groupby((s1 != 1).cumsum()).cumcount()
0 0
1 1
2 0
3 1
4 2
5 0
6 0
7 1
8 2
9 3
10 0
dtype: int64
更好的解释:
df = pd.DataFrame(s1, columns=['orig'])
df['not1'] = s1 != 1
df['cumsum'] = (s1 != 1).cumsum()
df['cumcount'] = s1.groupby((s1 != 1).cumsum()).cumcount()
#s1.groupby((s1 != 1).cumsum()).cumcount() is same as:
df['cumcount1'] = df.groupby('cumsum')['orig'].cumcount()
print df
orig not1 cumsum cumcount cumcount1
0 5 True 1 0 0
1 1 False 1 1 1
2 3 True 2 0 0
3 4 True 3 0 0
4 1 False 3 1 1
5 1 False 3 2 2
6 2 True 4 0 0
7 3 True 5 0 0
8 1 False 5 1 1
9 1 False 5 2 2
10 1 False 5 3 3
11 4 True 6 0 0
或者:
print (s1 == 1) * (s1.groupby((s1 != s1.shift()).cumsum()).cumcount() + 1)
0 0
1 1
2 0
3 1
4 2
5 0
6 0
7 1
8 2
9 3
10 0
dtype: int64
解释:
df = pd.DataFrame(s1, columns=['orig'])
df['compare_shift'] = s1 != s1.shift()
df['cumsum'] = (s1 != s1.shift()).cumsum()
df['cumcount'] = s1.groupby((s1 != s1.shift()).cumsum()).cumcount() + 1
df['cumcount1'] = df.groupby('cumsum')['orig'].cumcount() + 1
df['is1'] = (s1 == 1)
#True in converted to 1, False to 0
df['fin'] = (s1 == 1) * (s1.groupby((s1 != s1.shift()).cumsum()).cumcount() + 1)
print df
orig compare_shift cumsum cumcount cumcount1 is1 fin
0 5 True 1 1 1 False 0
1 1 True 2 1 1 True 1
2 3 True 3 1 1 False 0
3 4 True 4 1 1 False 0
4 1 True 5 1 1 True 1
5 1 False 5 2 2 True 2
6 2 True 6 1 1 False 0
7 3 True 7 1 1 False 0
8 1 True 8 1 1 True 1
9 1 False 8 2 2 True 2
10 1 False 8 3 3 True 3
11 4 True 9 1 1 False 0