首页 > 解决方案 > 我可以在这里应用矢量化吗?还是我应该换个角度思考这个问题?

问题描述

简而言之,我在一年中的某个特定月份发生了多行活动。我想在此活动之间添加额外的不活动行,同时将月份值重置为序列。例如,如果我有 2、5、7 个月,我需要将它们映射到 1、4、7,而我的非活动月份发生在 2、3、5 和 6。所以,我必须添加四行这种不活动。我已经使用字典和 for 循环完成了这项工作,但我知道这效率不高,尤其是当我将其移动到数千行数据进行处理时。关于如何优化它的任何建议?我是否需要以不同的方式考虑数据格式?我曾建议制作列表,然后将其移至最后的数据框,但我认为那里并没有很大的收获。我对 NumPy 的了解还不够,无法弄清楚如何通过矢量化来做到这一点,因为那 s 超级快,学习新东西会很棒。以下是我采取的步骤的代码:

df = pd.DataFrame({'col1': ['A','A', 'B','B','B','C','C'], 'col2': ['X','Y','X','Y','Z','Y','Y'], 'col3': [1, 8, 2, 5, 7, 6, 7]})

输出:

  col1 col2  col3
0    A    X     1
1    A    Y     8
2    B    X     2
3    B    Y     5
4    B    Z     7
5    C    Y     6
6    C    Y     7

我正在创建一个字典来处理这个 for 循环:

df1 = df.groupby('col1')['col3'].apply(list).to_dict()
df2 = df.groupby('col1')['col2'].apply(list).to_dict()
max_num = max(df.col3)

输出:

{'A': [1, 8], 'B': [2, 5, 7], 'C': [6, 7]}
{'A': ['X', 'Y'], 'B': ['X', 'Y', 'Z'], 'C': ['Y', 'Y']}
8

现在我通过创建一个新的数据框使用我的字典添加这些行:

df_new = pd.DataFrame({'col1': [], 'col2': [], 'col3': []})
for key in df1.keys():
    k = 1
    if list(df1[key])[-1] - list(df1[key])[0] + 1 < max_num:
        for i in list(range(list(df1[key])[0], list(df1[key])[-1] + 1, 1)):
            if i in df1[key]:
                df_new = df_new.append({'col1': key, 'col2': list(df2[key])[list(df1[key]).index(i)],'col3': str(k)}, ignore_index=True)
            else:
                df_new = df_new.append({'col1': key, 'col2': 'N' ,'col3': str(k)}, ignore_index=True)
            k += 1
        df_new = df_new.append({'col1': key, 'col2': 'E', 'col3': str(k)}, ignore_index=True)
    else:
        for i in list(range(list(df1[key])[0], list(df1[key])[-1] + 1, 1)):
            if i in df1[key]:
                df_new = df_new.append({'col1': key, 'col2': list(df2[key])[list(df1[key]).index(i)],'col3': str(k)}, ignore_index=True)
            else:
                df_new = df_new.append({'col1': key, 'col2': 'N' ,'col3': str(k)}, ignore_index=True)
            k += 1

输出:

   col1 col2 col3
0     A    X    1
1     A    N    2
2     A    N    3
3     A    N    4
4     A    N    5
5     A    N    6
6     A    N    7
7     A    Y    8
8     B    X    1
9     B    N    2
10    B    N    3
11    B    Y    4
12    B    N    5
13    B    Z    6
14    B    E    7
15    C    Y    1
16    C    Y    2
17    C    E    3

然后我转向我想要的形式:

df_pivot = df_new.pivot(index='col1', columns='col3', values='col2')

输出:

col3    1   2   3   4   5   6   7   8
col1                                
A   X   N   N   N   N   N   N   Y
B   X   N   N   Y   N   Z   E   NaN
C   Y   Y   E   NaN NaN NaN NaN NaN

谢谢您的帮助。

标签: python-3.xpandasnumpyfor-loopif-statement

解决方案


我们可以用下面的语句替换创建和使用字典的步骤,该语句reindex用于放置附加值N并且E没有显式循环。

df_new = df.set_index('col3')\
           .groupby('col1')\
           .apply(lambda dg:
                         dg.drop('col1', 1)
                           .reindex(range(dg.index.min(), dg.index.max()+1), fill_value='N')
                           .reindex(range(dg.index.min(), min(max_num, dg.index.max()+1)+1), fill_value='E')
                           .set_index(pd.RangeIndex(1, min(max_num, dg.index.max()-dg.index.min()+1+1)+1, name='col3'))
                 )\
           .reset_index()

在此之后,您可以pivot按原样应用您的声明。


推荐阅读