pandas 如何快速填充序列

5lwkijsr  于 2022-12-09  发布在  其他
关注(0)|答案(3)|浏览(131)

我有一个关于如何在Python中快速填充序列的问题(Pandas)。我有一个如下的数据集(真正的数据集更长),
| 时间|编号|
| - -|- -|
| 时间0|不适用|
| t1层|不适用|
| 第二次|不适用|
| t3层|第0页|
| t4级|不适用|
| t5级|不适用|
| t6级|不适用|
| 七号线|不适用|
| 八度|第0页|
| 九号线|不适用|
我的要求是在非空行的前后N行加上数字,顺序范围为range(-N,N+1),数据集中任意两个非空行之间的间隔大于C(常数),我们的N就会未来C,所以暂时不需要考虑覆盖问题,假设N=2,我需要的结果如下:
| 时间|编号|
| - -|- -|
| 时间0|不适用|
| t1层|-2个|
| 第二次|-1个|
| t3层|第0页|
| t4级|一个|
| t5级|2个|
| t6级|-2个|
| 七号线|-1个|
| 八度|第0页|
| 九号线|一个|
目前我能想到的唯一办法就是用循环,但是效率很低,Pandas有没有这样的方法可以快速做到?

vx6bjr1n

vx6bjr1n1#

在你的问题中还有一些未知数,比如如果区间重叠会发生什么。这里我将考虑下一个区间覆盖前一个区间(你可以通过改变代码来做相反的事情,见第二部分)。
使用rollinggroupby.cumcountmask

s = df['Number'].notna().shift(-N, fill_value=False)
m = s.rolling(2*N+1, min_periods=1).max().astype(bool)

df['Number2'] = df.groupby(s.cumsum()).cumcount().sub(N).where(m)
  • 注:我使用了一个稍微不同的示例来显示重叠。*

输出:

Time  Number  Number2
 0   t0     NaN      NaN
 1   t1     NaN     -2.0
 2   t2     NaN     -1.0
 3   t3     0.0      0.0
 4   t4     NaN      1.0
 5   t5     NaN     -2.0  # here we have an overlap, use latter value
 6   t6     NaN     -1.0
 7   t7     0.0      0.0
 8   t8     NaN      1.0
 9   t9     NaN      2.0
10  t10     NaN      NaN
第一组优先级
s = df['Number'].notna().shift(N, fill_value=False)[::-1]
m = s.rolling(2*N+1, min_periods=1).max().astype(bool)

df['Number3'] = df.groupby(s.cumsum()).cumcount(ascending=False).rsub(N).where(m)

输出:

Time  Number  Number2  Number3
0    t0     NaN      NaN      NaN
1    t1     NaN     -2.0     -2.0
2    t2     NaN     -1.0     -1.0
3    t3     0.0      0.0      0.0
4    t4     NaN      1.0      1.0
5    t5     NaN     -2.0      2.0  # difference in behavior
6    t6     NaN     -1.0     -1.0
7    t7     0.0      0.0      0.0
8    t8     NaN      1.0      1.0
9    t9     NaN      2.0      2.0
10  t10     NaN      NaN      NaN
q8l4jmvw

q8l4jmvw2#

n=2
col1=df1.Number.shift(-n).eq(0).cumsum()
df1.loc[col1!=0,'Number']=df1.loc[col1!=0].groupby(col1).transform('cumcount')-n
df1

输出功率

Time  Number
0   t0     NaN
1   t1    -2.0
2   t2    -1.0
3   t3     0.0
4   t4     1.0
5   t5     2.0
6   t6    -2.0
7   t7    -1.0
8   t8     0.0
9   t9     1.0
zxlwwiss

zxlwwiss3#

我们能多了解一些情况吗?
我注意到在你的最终结果t0仍然是NA,这是为什么?你仍然想保留一些值为NaN吗?
在这个例子中,t3最初是0,而在结果中它仍然是0,这在序列中是有意义的。而不是用0,而是用另一个像5的值?你是想保留5,还是从序列中的那个位置赋值0?如果你保留了5,那么t4会是0吗?
以下是一些解决方案,以防万一:

使用序列填充NaN值(跳过填充的值)

#!/usr/bin/env python 
import pandas as pd

df = pd.DataFrame([
    {'Time': 't0', 'Number': None},
    {'Time': 't1', 'Number': None},
    {'Time': 't2', 'Number': None},
    {'Time': 't3', 'Number': 0},
    {'Time': 't4', 'Number': None},
    {'Time': 't5', 'Number': None},
])

len_null = df['Number'].isna().sum()
starting_number = -2

df.loc[df['Number'].isna(), 'Number'] = list(range(starting_number, len_null-abs(starting_number)))

print(df)

会给予你这个:

Time  Number
0   t0    -2.0
1   t1    -1.0
2   t2     0.0
3   t3     0.0
4   t4     1.0
5   t5     2.0

用序列填充整列(覆盖填充的值)

#!/usr/bin/env python

import pandas as pd

df = pd.DataFrame([
    {'Time': 't0', 'Number': None},
    {'Time': 't1', 'Number': None},
    {'Time': 't2', 'Number': None},
    {'Time': 't3', 'Number': 0},
    {'Time': 't4', 'Number': None},
    {'Time': 't5', 'Number': None},
])

starting_number = -2
df['Number'] = list(range(starting_number, len(df)-abs(starting_number)))
print(df)

将为您提供:

Time  Number
0   t0      -2
1   t1      -1
2   t2       0
3   t3       1
4   t4       2
5   t5       3

使用序列填充NAN值(跳过填充值的序列)

#!/usr/bin/env python

import pandas as pd

df = pd.DataFrame([
    {'Time': 't0', 'Number': None},
    {'Time': 't1', 'Number': None},
    {'Time': 't2', 'Number': None},
    {'Time': 't3', 'Number': 0},
    {'Time': 't4', 'Number': None},
    {'Time': 't5', 'Number': None},
])

starting_number = -2
new_series = pd.Series(list(range(starting_number, len(df)-abs(starting_number))))
df['Number'] = df['Number'].fillna(new_series)
print(df)

将为您提供:

Time  Number
0   t0    -2.0
1   t1    -1.0
2   t2     0.0
3   t3     0.0
4   t4     2.0
5   t5     3.0

(请注意,1应该已经进入t3插槽,但由于那里已经有一个0,所以它只是跳过了它)

相关问题