首页 > 解决方案 > 如何有效地将数据框中的 pd.Series 列表更改为 np.arrays 的 pd.Series

问题描述

我有一个 PostgreSQL 数据库,其数据类似于:日期、字符变化、字符变化、整数 [] 在整数数组列中存储了一个值列表:1、2、3、4、5 我正在使用 pd.read_sql将数据读入数据帧。

所以我有一个数据框,其中包含一个日期列、几个字符串列,然后是一个包含整数列表的列。

数组值经常在 numpy 数组中用于进行向量数学运算。

在过去,我找不到将列表列转换为 numpy 数组列而不逐行循环和重新创建数据帧的方法。举个例子:

import pandas as pd
import numpy as np

col1 = ['String data'] * 4
col2 = [[1,2,3,4,5]] * 4
d = {'Description': col1, 'Measures':col2}
df = pd.DataFrame(d)

new_df = pd.DataFrame(columns=df.columns)

for i in range(len(df)):
    new_df.loc[i, ['Description','Measures']] = [df.at[i,'Description'], np.array(df.at[i,'Measures'])]

print(new_df)

这种循环可能超过几千行。

最近,我发现如果我可以对 Series -> list -> nparray -> list -> Series 进行单行转换并更有效地实现结果。

import pandas as pd
import numpy as np

col1 = ['String data'] * 4
col2 = [[1,2,3,4,5]] * 4
d = {'Description': col1, 'Measures':col2}
df = pd.DataFrame(d)

df['NParray'] = pd.Series(list(np.array(list(np.array(df['Measures'])))))
df.drop(['Measures'], axis=1, inplace=True)

print(df)
print(type(df['NParray'][0]))

我阅读并尝试使用 Series.array 和 Series.to_numpy,但它们并没有真正实现我想要做的事情。

所以,问题是:有没有一种方法可以将 pd.Series 列表转换为 numpy 数组,就像我正在尝试做的那样?有没有更简单的方法可以将这些列表批量转换为 numpy 数组?

我希望像这样简单的东西:

df['NParray'] =np.asarray(df['Measures'])
df['NParray'] =np.array(df['Measures'])
df['NParray'] =df['Measures'].array
df['NParray'] =df['Measures'].to_numpy()

但这些有不同的功能,不适合我的目的。

------------测试后编辑----------------------- -------------

我设置了一个小测试,看看时间和效率的差异是什么:

import pandas as pd
import numpy as np

def get_dataframe():
    col1 = ['String data'] * 10000
    col2 = [list(range(0,5000))] * 10000
    d = {'Description': col1, 'Measures':col2}
    df = pd.DataFrame(d)
    return(df)


def old_looping(df):
    new_df = pd.DataFrame(columns=df.columns)
    starttime = pd.datetime.now()
    for i in range(len(df)):
        new_df.loc[i, ['Description','Measures']] = [df.at[i,'Description'], np.array(df.at[i,'Measures'])]
    endtime = pd.datetime.now()
    duration = endtime - starttime
    print('Looping', duration)


def series_transforms(df):
    starttime = pd.datetime.now()
    df['NParray'] = pd.Series(list(np.array(list(np.array(df['Measures'])))))
    df.drop(['Measures'], axis=1, inplace=True)
    endtime = pd.datetime.now()
    duration = endtime - starttime
    print('Transforms', duration)


def use_apply(df):
    starttime = pd.datetime.now()
    df['Measures'] = df['Measures'].apply(np.array)
    endtime = pd.datetime.now()
    duration = endtime - starttime
    print('Apply', duration)


def run_test(tests):
    for i in range(tests):
        construct_df = get_dataframe()
        old_looping(construct_df)
    for i in range(tests):
        construct_df = get_dataframe()
        series_transforms(construct_df)
    for i in range(tests):
        construct_df = get_dataframe()
        use_apply(construct_df)

run_test(5)

10,000 行的结果是: 转换 3.945816
转换 3.968821
转换 3.891866
转换 3.859437
转换 3.860590

申请 4.218867
申请 4.015742
申请 4.046986
申请 3.906360
申请 3.890740

循环 27.662418
循环 27.814523
循环 27.298895
循环 27.565626
循环 27.222970

通过 Series-List-NP Array-List-Series 进行转换比使用 Apply 快得可以忽略不计。Apply 绝对是更短的代码并且可能更容易理解。

增加行数或数组长度将使时间增加相同的数量。

标签: pythonpandasnumpyseries

解决方案


最简单的可能是使用 apply 转换为 np.array:df['Measures'].apply(np.array)

完整示例:

import pandas as pd
import numpy as np

col1 = ['String data'] * 4
col2 = [[1,2,3,4,5]] * 4
d = {'Description': col1, 'Measures':col2}
df = pd.DataFrame(d)
display(df.Measures)

df['NParray'] = df['Measures'].apply(np.array)
df.drop(['Measures'], axis=1, inplace=True)

print(df)
print(type(df['NParray'][0]))

推荐阅读