Python / Pandas中的快速数据框标准化

时间:2020-02-16 10:22:05

标签: python pandas dataframe normalization

在Python / Pandas中,我尝试使用以下代码将数据框的所有数字列标准化为百万分之一:

import pandas as pd
def normalize(df):
    numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
    numeric_cols = [col for col in df.columns if df[col].dtype in numerics]
    sums = df.sum(axis=0, skipna = True)
    for col in numeric_cols:
        df.insert(df.columns.get_loc(col)+1, col+'_norm', ((df[col]/sums[col])*1000000)+1)
    return df
dataset = pd.read_csv(csv_file, index_col=['Guide1', 'Guide2'], sep=',')
dataset = normalize(dataset)

这是一个简短的示例输入:

Guide1,Guide2,Gene1,Gene2,NHT1,NHT2,hart_essential_1,hart_essential_2,lib,RPE1_n1,RPE1_n2,RPE1_n3
Gene_1-KO-3,Non-Human-Target-150-KO-26,Gene_1,Non-Human-Target-150,False,True,False,False,12426.0,10634.0,8701.0,8084.0
Gene_2-KO-3,Non-Human-Target-150-KO-26,Gene_2,Non-Human-Target-150,False,True,False,False,12300.0,12383.0,6252.0,5388.0
Gene_1-KO-3,Gene_4-KO-2,Gene_1,Gene_4,False,False,False,False,11685.0,10006.0,10621.0,7002.0
Gene_1-KO-3,Gene_5-KO-2,Gene_1,Gene_5,False,False,False,False,11347.0,6726.0,3927.0,3943.0
Gene_1-KO-3,Gene_6-KO-1,Gene_1,Gene_6,False,False,False,False,11250.0,12469.0,3552.0,3334.0    

该代码按预期工作并对该数据帧的所有数字列进行规范化,但它与其他规范化方法一起使用的速度似乎非常慢。我经常使用包含多达几百万行的数据框。对于约100万行和仅4个数字列,在我的移动计算机上使用Intel Core i7-6600U @ 2.6GHz进行归一化大约需要10分钟,尽管我会预先计算每列的总和。 有没有办法加快速度,例如并行化或一些巧妙的Pandas技巧?

非常感谢任何帮助和/或指针!

2 个答案:

答案 0 :(得分:0)

此代码修改中的规范化几乎是瞬时的。大部分时间都花在生成那些随机数上……

import pandas as pd
import random

numeric_dtypes = {'int16', 'int32', 'int64', 'float16', 'float32', 'float64'}

# Generate data...
n = 1000000
floats = [random.uniform(0, 100000) for x in range(n)]
ints = [int(i) for i in floats]
df = pd.DataFrame()
for dtype in numeric_dtypes:
    df[dtype] = pd.Series((ints if 'int' in dtype else floats), dtype=dtype)

# Normalize...
sums = df.sum(axis=0, skipna=True)
for col in df.columns:
    if str(df[col].dtype) not in numeric_dtypes:
        continue
    df[col + "_norm"] = df[col] / sums[col] * 1000000 + 1

print(df)

答案 1 :(得分:0)

感谢您抽出宝贵时间回答我!我想出了另一个我想分享的解决方案。 YaoYao启发了我测试多处理库以解决我的问题。以下解决方案运行速度非常快。该脚本首先读取.csv文件,确定数字列的名称并计算其总和。然后,它将数据集分成大小相等的块,并将归一化函数映射到每个块。将生成的标准化数据帧串联起来,以产生整个标准化数据集。

import pandas as pd
import math
import numpy as np
from multiprocessing import Pool

def index_marks(nrows, chunk_size):
    return range(chunk_size, math.ceil(nrows / chunk_size) * chunk_size, chunk_size)

def split(dfm, chunk_size):
    indices = index_marks(dfm.shape[0], chunk_size)
    return np.split(dfm, indices)

def normalize(df, sums, numeric_cols):
    for col in numeric_cols:
        df.insert(df.columns.get_loc(col)+1, col+'_norm', ((df[col]/sums[col])*1000000)+1)
    return df

def parallel_normalize(data):
    df = data[0]
    sums = data[1]
    numeric_cols = data[2]

    df = normalize(df, sums, numeric_cols)
    return df

numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
dataset_file = '/path/to/file.csv'

cores = 3

dataset = pd.read_csv(dataset_file, index_col=['Guide1', 'Guide2'], sep=',')
dataset = dataset.fillna(0.0)

numeric_cols = [col for col in dataset.columns if dataset[col].dtype in numerics]
sums = dataset[numeric_cols].sum(axis=0, skipna = True)

chunks = split(dataset, int(round(dataset.shape[0]/cores)))
pool = Pool(cores)
dataset = pd.concat(pool.map(parallel_normalize, [[x, sums, numeric_cols] for x in chunks]))
pool.close()
pool.join()

我不知道为什么加速如此之大。我本来希望将加速60%,因为我将数据分为3个块。但是它实际上是瞬时运行的。如果有人可以在这里发表评论并提供一些见识,我会非常高兴!