【问题标题】:How to assign values to cells of a dataframe efficiently iterating over another object如何为数据框的单元格分配值有效地迭代另一个对象
【发布时间】:2019-02-24 08:58:52
【问题描述】:

我得到了一个生成器对象,它基本上由嵌套列表组成。 它包含大约 20.000 个列表,结构如下所示:

cases = [[0,36,12],[64,28,1],....

此对象中的每个列表代表属于一个进程的行。现在我想将 ProcessID 分配给数据帧的相应行。在我使用 for 循环实现这一点的那一刻:

moc = df.iloc
processID = 0 
for process in cases:
  for step in process:
    moc[process,-1] = processID
  processID += 1

尽管这可行,但遍历 for 循环需要很长时间,因此我对分配 processID 的更有效方法感兴趣。

由于我需要遍历 case 对象,并且由于嵌套列表的长度不同,我不知道如何实现更高效的过程,例如 df.apply() 或 np.where()。

感谢任何帮助。

例子:

import pandas as pd
import numpy as np

cases = [[1,4,2],[3,5,0],[9,6],[7,8]]


d = {'col1': ["some_information", "some_information","some_information",
              "some_information","some_information","some_information", 
              "some_information","some_information","some_information",
              "some_information"],
    'processID':np.empty}

df = pd.DataFrame(data=d)

print(df)
               col1                  processID
0  some_information  <built-in function empty>
1  some_information  <built-in function empty>
2  some_information  <built-in function empty>
3  some_information  <built-in function empty>
4  some_information  <built-in function empty>
5  some_information  <built-in function empty>
6  some_information  <built-in function empty>
7  some_information  <built-in function empty>
8  some_information  <built-in function empty>
9  some_information  <built-in function empty>

moc = df.iloc
processID = 1
for case in cases:
    for idx in case:
        moc[idx,-1] = processID

    processID += 1


print(df)
               col1 processID
0  some_information         2
1  some_information         1
2  some_information         1
3  some_information         2
4  some_information         1
5  some_information         2
6  some_information         3
7  some_information         4
8  some_information         4
9  some_information         3

【问题讨论】:

  • 您能否提供一个最小的可重现示例。

标签: pandas for-loop dataframe processing-efficiency


【解决方案1】:

IIUC,这里有一个解决方案,它使用带有Index.repeatnumpy.hstack 的字典理解来创建pandas.Series,您可以使用它来更新您的DataFrame。这样做的好处是没有循环。

s = pd.Series({(i+1):x for i, x in enumerate(cases)})
processes = pd.Series(s.index.repeat(s.str.len()), index=np.hstack(s))

根据您的示例cases,这将创建一个Series“进程”,例如:

1    1
4    1
2    1
3    2
5    2
0    2
9    3
6    3
7    4
8    4

然后你可以分配到你的DataFrame:

df['processID'] = processes

测试性能

设置 - 创建 len 100,000 和随机 cases 列表的 DataFrame:

idx = pd.Series(np.arange(100000)).sample(frac=1).values.tolist()
cases = [idx[i:i + 3] for i in range(0, len(idx), 3)]

df=pd.DataFrame({'col1':np.arange(100000),
                 'col2':['some_data']*100000})

时间

%%timeit

s = pd.Series({(i+1):x for i, x in enumerate(cases)}).to_frame()
processes = pd.Series(s.index.repeat(s[0].str.len()), index=np.hstack(s[0]))
df['processID'] = processes

92.2 ms ± 1.79 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

【讨论】:

    猜你喜欢
    • 2014-08-07
    • 1970-01-01
    • 2018-04-01
    • 2019-05-21
    • 2020-10-02
    • 2018-01-16
    • 2020-10-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多