Python 将函数应用于dataframe中的每两列,并用输出替换原始列

Python 将函数应用于dataframe中的每两列,并用输出替换原始列,python,pandas,dataframe,numpy,Python,Pandas,Dataframe,Numpy,我有一个数据框,其中包含以下列中的X&Y数据: df_cols = ['x1', 'y1', 'x2', 'y2', 'x3', 'y3'] np.random.seed(365) df = pd.DataFrame(np.random.randint(0,10,size=(10, 6)), columns=df_cols) x1 y1 x2 y2 x3 y3 0 2 4 1 5 2 2 1 9 8 4 0 3 3 2 7

我有一个数据框,其中包含以下列中的X&Y数据:

df_cols = ['x1', 'y1', 'x2', 'y2', 'x3', 'y3']

np.random.seed(365)
df = pd.DataFrame(np.random.randint(0,10,size=(10, 6)), columns=df_cols)

   x1  y1  x2  y2  x3  y3
0   2   4   1   5   2   2
1   9   8   4   0   3   3
2   7   7   7   0   8   4
3   3   2   6   2   6   8
4   9   6   1   6   5   7
5   7   6   5   9   3   8
6   7   9   9   0   1   4
7   0   9   6   5   6   9
8   5   3   2   7   9   2
9   6   6   3   7   7   1
我需要调用一个函数,该函数一次获取一个X&Y对,并返回和更新X&Y对(相同长度),然后用原始列名将该数据保存到新的数据框中,或者用新数据替换旧的X&Y数据并保留原始列名

例如,以下面的函数为例:

def samplefunc(x, y):
    x = x*y
    y = x/10
    return x, y

# Apply function to each x & y pair 
x1, y1 = samplefunc(df.x1, df.y1)
x2, y2 = samplefunc(df.x2, df.y2)
x3, y3 = samplefunc(df.x3, df.y3)

 # Save new/updated x & y pairs into new dataframe, preserving the original column names 
df_updated = pd.DataFrame({'x1': x1, 'y1': y1, 'x2': x2, 'y2': y2, 'x3': x3, 'y3': y3})

# Desired result:
In [36]: df_updated
Out[36]: 
   x1   y1  x2   y2  x3   y3
0   8  0.8   5  0.5   4  0.4
1  72  7.2   0  0.0   9  0.9
2  49  4.9   0  0.0  32  3.2
3   6  0.6  12  1.2  48  4.8
4  54  5.4   6  0.6  35  3.5
5  42  4.2  45  4.5  24  2.4
6  63  6.3   0  0.0   4  0.4
7   0  0.0  30  3.0  54  5.4
8  15  1.5  14  1.4  18  1.8
9  36  3.6  21  2.1   7  0.7
但是,对于一个庞大的数据集来说,这样做显然是非常乏味和不可能的。 我发现的类似/相关问题对数据执行简单的转换,而不是调用函数,或者它们向数据帧添加新列,而不是替换原始列

我试图将@PaulH的答案应用于我的数据集,但这两种方法都不起作用,因为目前还不清楚如何实际调用这两种方法中的函数

# Method 1
array = np.array(my_actual_df)
df_cols = my_actual_df.columns
dist = 0.04 # a parameter I need for my function 
df = (
    pandas.DataFrame(array, columns=df_cols)
        .rename_axis(index='idx', columns='label')
        .stack()
        .to_frame('value')
        .reset_index()
        .assign(value=lambda df: numpy.select(
            [df['label'].str.startswith('x'), df['label'].str.startswith('y')],

            # Call the function (not working): 
            [df['value'], df['value']] = samplefunc(df['value'], df['value']),
        ))
        .pivot(index='idx', columns='label', values='value')
        .loc[:, df_cols]
)



# Method 2
df = (
    pandas.DataFrame(array, columns=df_cols)
        .pipe(lambda df: df.set_axis(df.columns.map(lambda c: (c[0], c[1])), axis='columns'))
        .rename_axis(columns=['which', 'group'])
        .stack(level='group')
         
        # Call the function (not working)
        .assign(df['x'], df['y'] = samplefunc(df['x'], df['y']))
        .unstack(level='group')
        .pipe(lambda df: df.set_axis([''.join(c) for c in df.columns], axis='columns'))
)

我需要调用的实际函数来自Arty对这个问题的回答:

有几种方法可以实现这一点,具体取决于实际数据帧的构造方式

我想到的第一件事是完全堆叠数据帧并使用
numpy。选择
根据标签的值计算新值。然后,可以将数据帧旋转回其原始形式:

导入numpy
进口大熊猫
df_cols=['x1','y1','x2','y2','x3','y3']
numpy.random.seed(365)
array=numpy.random.randint(0,10,size=(10,6))
df=(
pandas.DataFrame(数组,列=df_cols)
.rename_轴(index='idx',columns='label')
.stack()
.to_帧(“值”)
.reset_index()
.assign(值=λdf:numpy.select(
[df['label'].str.startswith('x'),df['label'].str.startswith('y'),
[df['value']**2,df['value']/10],
))
.pivot(index='idx',columns='label',values='value')
.loc[:,df_cols]
)
或者,您可以将列名视为层次结构,将其转换为多级索引,然后仅堆叠该索引的第二级。这样,您就得到了单独的x列和y列,可以直接显式地对其进行操作

df=(
pandas.DataFrame(数组,列=df_cols)
.pipe(lambda df:df.set_axis(df.columns.map(lambda c:(c[0],c[1])),axis='columns'))
.rename_轴(列=['哪个','组])
.stack(level='group')
.assign(x=lambda-df:df['x']**2,y=lambda-df:df['y']/10)
.unstack(level='group')
.pipe(lambda-df:df.set_轴(['''.join(c)表示df.columns中的c],axis='columns'))
)

使用切片并对这些切片应用操作

def samplefunc(x, y):
    x = x**2
    y = y/10
    return x, y

arr = df.to_numpy().astype(object) 
e_col = arr[:, ::2]
o_col =  arr[:, 1::2]
e_col, o_col = samplefunc(e_col, o_col)
arr[:, ::2] = e_col 
arr[:, 1::2] = o_col 
out = pd.DataFrame(arr, columns=df.columns)

   x1   y1  x2   y2  x3   y3
0   4  0.4   1  0.5   4  0.2
1  81  0.8  16  0.0   9  0.3
2  49  0.7  49  0.0  64  0.4
3   9  0.2  36  0.2  36  0.8
4  81  0.6   1  0.6  25  0.7
5  49  0.6  25  0.9   9  0.8
6  49  0.9  81  0.0   1  0.4
7   0  0.9  36  0.5  36  0.9
8  25  0.3   4  0.7  81  0.2
9  36  0.6   9  0.7  49  0.1
这里的新方法:

  • 将列拆分为多级索引
  • 做水平分组
  • 修改
    samplefunc
    以获取数据帧:
def samplefunc(df,xcol='x',ycol='y'):
x=df[xcol]。to_numpy()
y=df[ycol]。to_numpy()
df[xcol]=x*y
df[ycol]=x/10
返回df
df=(
pandas.DataFrame(数组,列=df_cols)
.pipe(lambda df:df.set_axis(df.columns.map(lambda c:(c[0],c[1])),axis='columns'))
.rename_轴(列=['哪个','组])
.groupby(level='group',axis='columns')
.apply(samplefunc)
.pipe(lambda-df:df.set_轴(['''.join(c)表示df.columns中的c],axis='columns'))
)
我得到:

   x1   y1  x2   y2  x3   y3
0   8  0.8   5  0.5   4  0.4
1  72  7.2   0  0.0   9  0.9
2  49  4.9   0  0.0  32  3.2
3   6  0.6  12  1.2  48  4.8
4  54  5.4   6  0.6  35  3.5
5  42  4.2  45  4.5  24  2.4
6  63  6.3   0  0.0   4  0.4
7   0  0.0  30  3.0  54  5.4
8  15  1.5  14  1.4  18  1.8
9  36  3.6  21  2.1   7  0.7

这回答了你的问题吗?如果函数对x和y列执行单独的操作,则可以添加一个条件来检查列名,并为x和y列选择不同的函数。这使得整个过程更加复杂easier@VirtualScooter谢谢,但它没有回答我的问题,因为它在原始数据帧中创建了一个新列,而不是用输出替换原始数据。它在添加新数据时也不会保留列名。@AmirMaleki我正在使用的实际函数需要同时使用两个x和y值作为输入,并返回两个更新的x和y值,以便在随机中添加种子,因此数据保持与您相同,我只是不确定如何在您提供的代码中包含实际调用函数。我在问题中加入了我的尝试。函数要求同时传递x&y,然后一起返回更新后的x&y数组。@CentauriAurelius我认为第二个方法是您想要的,但也不清楚如何在第二个方法中调用我的函数。我也在我的问题中加入了使用第二种方法的尝试。@CentauriAurelius
resample\u euclid\u equidist
来自哪里?这是我需要应用于df的实际函数。我刚刚编辑了调用“samplefunc”的代码。您可以编辑答案来调用我提供的示例函数吗?(samplefunc)@CentauriAurelius实际上不需要重塑,编辑了答案谢谢,这对我来说更容易理解,但唯一的问题是它一次通过所有偶数列和所有奇数列。我正在使用的函数要求每次传递一个X&Y对这对于简单的示例函数很好,但我真的希望得到一个不需要更改函数的答案(即,只需在每对2列上调用函数,然后返回两列)。我担心如果我试图更改重采样欧几里德均衡器函数,我会破坏它,或者调试它会花费很长时间,因为它是如此巨大和复杂(我充其量只是一个平庸的程序员)。@CentauriAurelius我更改函数的方式只是将数据帧列解包/打包到numpy数组中。开头有两行。最后两行。
   x1   y1  x2   y2  x3   y3
0   8  0.8   5  0.5   4  0.4
1  72  7.2   0  0.0   9  0.9
2  49  4.9   0  0.0  32  3.2
3   6  0.6  12  1.2  48  4.8
4  54  5.4   6  0.6  35  3.5
5  42  4.2  45  4.5  24  2.4
6  63  6.3   0  0.0   4  0.4
7   0  0.0  30  3.0  54  5.4
8  15  1.5  14  1.4  18  1.8
9  36  3.6  21  2.1   7  0.7