如何将函数快速应用于Pandas体内的每个细胞

2024-09-20 05:32:28 发布

您现在位置:Python中文网/ 问答频道 /正文

我的问题如下: 我需要对数据帧中的每个单元格应用一个操作。像这样,我有一个变量中所有数据帧的平均值和std列:

columnWiseMeans = df.mean(axis=0)
columnWiseStd = df.std(axis=0)

然后在每个单元格中都不是0,我将它们归一化:

for i in range(df.shape[0]):
  for j in range(df.shape[1]):
    if df.iloc[i, j] == 0:
        continue
    else:
        df.iloc[i, j] = (df.iloc[i, j]-columnWiseMeans[j])/columnWiseStd[j]
        print(f'in {i},{j} value {df.iloc[i, j]}')

按行收集平均值和标准值后,进行相同操作:

rowWiseMeans = df.mean(axis=1)
print(rowWiseMean[0])
rowWiseStd = df.std(axis=1)
print(rowWiseStd[0])

for i in range(df.shape[0]):

  for j in range(df.shape[1]):
    if df.iloc[i, j] == 0:
        continue
    else:
        df.iloc[i, j] = (df.iloc[i, j]-rowWiseMeans[i])/rowWiseStd[i]
        print(f'in {i},{j} value {df.iloc[i, j]}')

   

这里的问题是速度非常慢,因为我有一个[~70k,~70k]数据帧。我试过使用applymap,它速度更快,但我不知道如何告诉它如果是0,跳过它,让我知道在哪个位置使用特定的平均值和标准。有什么帮助吗?谢谢


Tags: 数据indfforrangemean平均值std
1条回答
网友
1楼 · 发布于 2024-09-20 05:32:28

首先,我看到您正在为每个元素分配元素,一般来说,操作整个数据帧会更快

我在我的机器上用numpy创建的(10k x 10k)数组运行了一些测试

import pandas as pd
import numpy as np
r = np.random.rand
  • 在2.5秒内生成数据
N = 10000
dnp = np.random.randn(N, N) * r(N, 1) * r(1, N) + r(1, N) + r(N, 1);
df = pd.DataFrame(dnp);
  • 使用数据帧计算6.5秒

这可能就是你想要的。对于您的数据帧,它将在大约5分钟内运行

df = (df - df.mean(axis=0)) / df.std(axis=0)
df = (df - df.mean(axis=1)) / df.std(axis=1)
  • 使用numpy进行更快的计算(3秒)

如果数据帧具有统一类型(例如,所有条目都是float64),则可以将其转换为numpy数组,使用numpy进行计算并返回到数据帧表示

dnp = np.array(df)
dnp[:,:] = (dnp - dnp.mean(axis=0)) / dnp.std(axis=0)
dnp[:,:] = (dnp - dnp.mean(axis=1)) / dnp.std(axis=1)
df = pd.DataFrame(np);

如果您可以使用32位数字,那么您可以执行 dnp = np.array(df, dtype=np.float32),它将在1.5秒内运行

Python循环

Python是被解释的,正如您在上面的解决方案中所看到的,您可以在一些Python指令中完成所有操作。在您的示例中,您正在运行几个循环。我看到您甚至检查了零以避免计算一个元素,这可能没有帮助,因为python中的每条指令都有开销。考虑下面的例子。

t = 0
for i in range(N):
    for j in range(N):
        t += 1

它比您的开销要小,并且需要10秒(对于10k x 10k矩阵)。使用N=70k运行大约需要9分钟

编辑1:避免nan

如注释中所述,某些行/列可能以nan结尾,这一定是一个0/0问题。当所有元素都说x[i] = c对于所有的i,这意味着mean(x) = cstd(x) = 0,因此(x[i] - mean(x))/std(x) = (c - c) / 0 = 0 / 0会发生这种情况

一种可能的解决方案是将这些值改为0。这可以在不产生重大额外成本的情况下实现,如下所示:

df = (df - df.mean(axis=0)) / df.std(axis=0).replace(0, 1)
df = (df - df.mean(axis=1)) / df.std(axis=1).replace(0, 1)

每当replace方法找到零时,它就会将结果设置为1,因此上面的表达式将变成(c - c) / 1 = 0

如果由于任何其他原因std正在生成nan,您可以使用fillna方法

df = (df - df.mean(axis=0)) / df.std(axis=0).fillna(1).replace(0, 1)
df = (df - df.mean(axis=1)) / df.std(axis=1).fillna(1).replace(0, 1)

此解决方案只是跳过标准偏差返回nan的行/列的规范化

相关问题 更多 >