Python 如何获取数据帧列中数字周围的值?

Python 如何获取数据帧列中数字周围的值?,python,pandas,dataframe,Python,Pandas,Dataframe,假设以下示例数据帧: df = pd.DataFrame([10,15,9,3,5,6,7,12,9], columns = ['numbers']).sort_values(by = 'numbers') 对于numbers列中的每个值,我希望获取该值及其周围的4数字。因此,只要可能,我希望比当前值小2个,大2个。当不可能时,我希望获取小于该值的k数字和大于该值的n数字,以便k+n=4 循环我的示例,第一个值是3。没有小于3的数字,因此输出为大于3的4个数字: 3,5,6,7,9 期望输出

假设以下示例数据帧:

df = pd.DataFrame([10,15,9,3,5,6,7,12,9], columns = ['numbers']).sort_values(by = 'numbers')

对于numbers列中的每个值,我希望获取该值及其周围的4数字。因此,只要可能,我希望比当前值小2个,大2个。当不可能时,我希望获取小于该值的k数字和大于该值的n数字,以便
k+n=4

循环我的示例,第一个值是3。没有小于3的数字,因此输出为大于3的4个数字:
3,5,6,7,9

期望输出: 输出列具有所需的输出,对应于数字列中的每个输入。(我使用引号突出显示当前值)


看看
pd.rolling()
pd.Series.shift()
。然后将第一个和最后一个n作为特例:

df.loc[[0:4],['n1','n2','n3','n4']] = df['numbers'][:4].values

我建议将每个新值设置为一列,而不是将其全部打包为一列,因为这样更容易使用。如果你愿意的话,你可以把它们浓缩成str。

我想不出一个聪明的方法来做这件事,但我认为这是可行的:

df2 =df.copy()
for i in range(-4, 5, 1):
    df2['{}_shifted'.format(str(i))] = df.numbers.shift(i)  #Here I'm making new columns to represent the shifted numbers

df2 =df2.drop('0_shifted', axis =1)  #dropping the 0_shifted column because it's the same as the `numbers` column
接下来我们要处理特殊情况,前两排和后两排

nums = []
for i,j,in enumerate( df2.iterrows()):
     if np.isnan((j[1][-2])):
       nums.append(list(j[1])[i+1:i+5])

     elif np.isnan((j[1][2])):

        nums.append((list(j[1])[i-3:i+1]))


     else:

         nums.append(list(j[1])[len(list(j[1]))//2 -1:len(list(j[1]))//2 +3 ])
上面的代码将返回一个列表,
nums
,我们将它做成一个系列,并连接到原始数据帧

close_numbers =pd.Series(nums, index = df.index)


pd.concat((df, close_numbers), axis =1)
这在一般情况下也适用。在某些情况下,它可能会断裂,需要稍微调整。也许有一种更聪明的方法可以想出更好的解决方案;想不出一个聪明的办法

让我知道它是否有效


谢谢

如果你想为自己的学习体验编写程序,一个非常简单的方法是

def rollingWindow(x, size=2):
    n = len(x)
    results = []
    for i in range(n):
        temp = (x[i], x[:i][-size:], x[i:][1:(size+1)])
        results.append(temp)
        print(temp) ## only for show
    return results
如果要传递一个简单的数字列表0到9,那么

>>> rollingWindow(range(10))
(0, [], [1, 2])
(1, [0], [2, 3])
(2, [0, 1], [3, 4])
(3, [1, 2], [4, 5])
(4, [2, 3], [5, 6])
(5, [3, 4], [6, 7])
(6, [4, 5], [7, 8])
(7, [5, 6], [8, 9])
(8, [6, 7], [9])
(9, [7, 8], [])
如您所见,对于第一行,只返回一个空列表,因为0之前没有任何内容。然后,对于下一行(
1
),返回
[0]
,因为
0
位于
1
之前

现在,如果您想将其应用于您的pandas数据帧,那么将
reset\u index(drop=True)
添加到行尾以重置索引

然后

如输出所示,对于第一行值
3
,没有过去的值,因此函数返回空列表,但也返回
[5,6]
,因为这些是未来的值。然后对于下一行,
5
,函数返回
[0]
作为过去值,返回
[6,7]
作为未来值。然后等等

然后,您可以修改它以适合您的目的。当然,这只是一个例子,绝不意味着它是“最终的”。

设置

df = pd.DataFrame([10,15,9,3,5,6,7,12,9], columns = ['numbers']).sort_values(by = 'numbers')
解决方案

#reset index so it's sorted
df.reset_index(inplace=True)

#build reference index lists
start = [0,1]+[2]*(len(df)-4)+[3,4]
end = start[::-1]

#Extract elements based on the start and end reference index.
df['output'] = df.apply(lambda x: sum([df.iloc[x.name-start[x.name]:x.name]['numbers'].tolist(),
                  [x['numbers']],df.iloc[x.name+1:x.name+end[x.name]+1]['numbers'].tolist()],[]), axis=1)

df
Out[610]: 
   index  numbers              output
0      3        3     [3, 5, 6, 7, 9]
1      4        5     [3, 5, 6, 7, 9]
2      5        6     [3, 5, 6, 7, 9]
3      6        7     [5, 6, 7, 9, 9]
4      2        9    [6, 7, 9, 9, 10]
5      8        9   [7, 9, 9, 10, 12]
6      0       10  [9, 9, 10, 12, 15]
7      7       12  [9, 9, 10, 12, 15]
8      1       15  [9, 9, 10, 12, 15]

'numbers'
列中的值是否唯一?如果不是,预期的输出是什么?它们不是唯一的。数字可以重复,就像我上面的例子一样。数字9重复。它不影响输出。输出列是什么?输出列的每一行都有一个数字列表?输出列是我想要的输出,对应于数字列中的每个输入。
df = pd.DataFrame([10,15,9,3,5,6,7,12,9], columns = ['numbers']).sort_values(by = 'numbers').reset_index(drop=True)

df.apply(rollingWindow, axis = 0)
Out[5]:
              numbers
0         (3, [], [5, 6])
1        (5, [3], [6, 7])
2     (6, [3, 5], [7, 9])
3     (7, [5, 6], [9, 9])
4    (9, [6, 7], [9, 10])
5   (9, [7, 9], [10, 12])
6  (10, [9, 9], [12, 15])
7     (12, [9, 10], [15])
8      (15, [10, 12], [])
df = pd.DataFrame([10,15,9,3,5,6,7,12,9], columns = ['numbers']).sort_values(by = 'numbers')
#reset index so it's sorted
df.reset_index(inplace=True)

#build reference index lists
start = [0,1]+[2]*(len(df)-4)+[3,4]
end = start[::-1]

#Extract elements based on the start and end reference index.
df['output'] = df.apply(lambda x: sum([df.iloc[x.name-start[x.name]:x.name]['numbers'].tolist(),
                  [x['numbers']],df.iloc[x.name+1:x.name+end[x.name]+1]['numbers'].tolist()],[]), axis=1)

df
Out[610]: 
   index  numbers              output
0      3        3     [3, 5, 6, 7, 9]
1      4        5     [3, 5, 6, 7, 9]
2      5        6     [3, 5, 6, 7, 9]
3      6        7     [5, 6, 7, 9, 9]
4      2        9    [6, 7, 9, 9, 10]
5      8        9   [7, 9, 9, 10, 12]
6      0       10  [9, 9, 10, 12, 15]
7      7       12  [9, 9, 10, 12, 15]
8      1       15  [9, 9, 10, 12, 15]