pandas遍历行并计算fas

2024-04-24 19:48:26 发布

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

我已经有了一个解决方案-但它非常慢(800行13分钟)。以下是数据帧的示例:

import pandas as pd
d = {'col1': [20,23,40,41,48,49,50,50], 'col2': [39,32,42,50,63,68,68,69]}
df = pd.DataFrame(data=d)
df

在一个新列中,我想计算col2的前几个值(例如三个)中有多少大于或等于col1的行值。我也继续第一排。你知道吗

这是我的慢代码:

start_at_nr = 3 #variable in which row start to calculate
df["overlap_count"] = "" #create new column

for row in range(len(df)):
    if row <= start_at_nr - 1:
       df["overlap_count"].loc[row] = "x"
    else:
       df["overlap_count"].loc[row] = (
           df["col2"].loc[row - start_at_nr:row - 1] >=
           (df["col1"].loc[row])).sum()

df

我得到一个更快的解决方案-谢谢你的时间!你知道吗

这是我得到的结果:

col1    col2    overlap_count
0   20  39  x
1   23  32  x
2   40  42  x
3   41  50  1
4   48  63  1
5   49  68  2
6   50  68  3
7   50  69  3

Tags: 数据in示例dfcount解决方案startnr
3条回答

基本上将当前值col1与前3行col2进行比较,然后从第3行开始比较。您可以按如下方式使用班次

n = 3
s = ((pd.concat([df.col2.shift(x) for x in range(1,n+1)], axis=1) >= df.col1.values[:,None])
        .sum(1)[3:])

或者

s = (pd.concat([df.col2.shift(x) for x in range(1,n+1)], axis=1).ge(df.col1,axis=0)
                                                                .sum(1)[3:])


Out[65]:
3    1
4    1
5    2
6    3
7    3
dtype: int64

要获得所需的输出,请将其分配回dffillna

n = 3
s = (pd.concat([df.col2.shift(x) for x in range(1,n+1)], axis=1).ge(df.col1,axis=0)
                                                                .sum(1)[3:])
df_final = df.assign(overlap_count=s).fillna('x')

Out[68]:
   col1  col2 overlap_count
0    20    39             x
1    23    32             x
2    40    42             x
3    41    50             1
4    48    63             1
5    49    68             2
6    50    68             3
7    50    69             3

您可以在一条语句中使用.apply()来完成它,如下所示。我使用了一个便利函数process_row(),它也包含在下面。你知道吗

df.assign(OVERLAP_COUNT = (df.reset_index(drop=False).rename(
                                columns={'index': 'ID'})).apply(
                                    lambda x: process_row(x, df, offset=3), axis=1))

For More Speed: In case you need more speed and are processing a lot of rows, you may consider using swifter library. All you have to do is:

  • install swifter: pip install swifter.
  • import the library as import swifter.
  • replace any .apply() with .swifter.apply() in the code-block above.

详细解决方案

#!pip install -U swifter
#import swifter 
import numpy as np
import pandas as pd

d = {'col1': [20,23,40,41,48,49,50,50], 'col2': [39,32,42,50,63,68,68,69]}
df = pd.DataFrame(data=d)

def process_row(x, df, offset=3):
    value = (df.loc[x.ID - offset:x.ID - 1, 'col2'] >= df.loc[x.ID, 'col1']).sum() if (x.ID >= offset) else 'x'
    return value

# Use df.swifter.apply() for faster processing, instead of df.apply()
df.assign(OVERLAP_COUNT = (df.reset_index(drop=False, inplace=False).rename(
                                columns={'index': 'ID'}, inplace=False)).apply(
                                    lambda x: process_row(x, df, offset=3), axis=1))

输出

   col1  col2 OVERLAP_COUNT
0    20    39             x
1    23    32             x
2    40    42             x
3    41    50             1
4    48    63             1
5    49    68             2
6    50    68             3
7    50    69             3

IIUC,你可以做:

df['overlap_count'] = 0
for i in range(1,start_at_nr+1):
    df['overlap_count'] += df['col1'].le(df['col2'].shift(i))

# mask the first few rows
df.iloc[:start_at_nr, -1] = np.nan

输出:

   col1  col2  overlap_count
0    20    39            NaN
1    23    32            NaN
2    40    42            NaN
3    41    50            1.0
4    48    63            1.0
5    49    68            2.0
6    50    68            3.0
7    50    69            3.0

对于800行和start_at_nr=3,大约需要11毫秒。你知道吗

相关问题 更多 >