繁体   English   中英

根据初始行中的值将熊猫数据帧的多行合并为一行,向该行添加新列的最有效方法?

[英]Most efficient way to merge multiple rows of a pandas dataframe in to one row, adding new columns to the row, based on values in the initial rows?

我有一个由受众特征和调查问题与答案组成的熊猫数据框。 问题是多项选择和多项选择。 初始数据帧中的每一行表示单个问题的单个答案。 因此,每个受访者和每个问题都有多行。 初始数据帧如下所示:

user_id  question    answer   age  gender
1        question_1  answer3  34   male
1        question_1  answer5  34   male
1        question_2  answer1  34   male
1        question_2  answer4  34   male
2        question_1  answer1  22   female
2        question_1  answer3  22   female

我想更改数据框,以便每一行代表一个受访者的所有答案。 在新数据框中,每个受访者只有一行,每个问题/答案组合只有一列。 如果受访者用相应的答案回答了问题,则问题/答案列的值将为1。 新的数据框应如下所示:

user_id  age  gender  q1_ans1  q1_ans3 q1_ans5 q2_ans1 q2_ans4
1        34   male    0        1       1       1       1
2        22   female  1        1       0       0       0

我试图通过创建一个新的数据框,使用itertuples()遍历每一行,检查新数据框是否包含相关受访者的行来实现此目的,如果没有,则在新数据框中使用新列,以当前行中问题和答案字段的组合命名,值为1,如果确实如此,则为被调查者找到该行并添加新列,将其命名为问题和答案的组合从当前行回答并将值设置为1。

问题在于,这非常慢。 是否有使用数据帧实现此目的的更有效方法? 如果没有,那么还有其他解决方案吗? 任何帮助都感激不尽。 代码如下:

def process_raw_df(self):
    raw_df = self.dc.get_data_frame()
    new_df = pd.DataFrame(columns=['user_id', 'occupation_label', 
                                   'relationship_label', 'age', 
                                   'income_tier', 'income',
                                   'has_children', 'country', 'city'])
    new_df.set_index('user_id')

    for row in raw_df.itertuples():
        new_column_name = str(row[2]) + str(row[3])
        if new_df.loc[new_df['user_id'] == row[0]]['user_id'].count() 
         == 0:
            new_row = [[row[1], row[4], row[5], row[6], row[7], row[8], 
                       row[9], row[10], row[11], 1]]
            new_row_df = pd.DataFrame(new_row, columns=['user_id', 
                  'occupation_label', 'relationship_label', 'age',
                  'income_tier', 'income', 'has_children', 'country', 
                  'city', new_column_name])
            new_df.append(new_row_df)
        else:
            new_df.loc[new_df['user_id'] == row[1], new_column_name] = 
            1
    return new_df

好了,这是未经优化的代码,可以做简单的事情。 您需要熊猫的应用功能。

尝试申请并轮换

如果答案存在,则新列应为标志:

df['new_column'] = df.apply(lambda x : return user_flagger(x[2])
df.pivot(index='userid', columns='question', values='newcolumn')

然后标记所有非0的答案,等等。 我将把它的确切编码部分留给您作为练习。 :)

编辑:由于列名对您很重要,因此请多留一个列,以连接列问题和列答案。 之后,重点介绍串联的列名和从标志器函数获得的值。 花几分钟阅读有关熊猫进化论的文章,​​我相信答案将会清楚。 如果您仍然无法执行操作,我将在此处发布有效代码。

码:

df['pivot_column']=df['question'].str.replace('question_','q')+'_'+df['answer'].str.replace('answer','ans')

df['flag']=1
df2 = df.pivot(index='user_id', columns='pivot_column', values='flag')

此解决方案有一个小问题-它不需要性别和年龄,请参阅下面的代码,看看该代码是否比按组执行的速度更快。 如果是这样,您可以通过加入来恢复年龄和性别。

让我们使用groupbyget_dummies

dfout = (df.groupby(['user_id','age','gender'])
          .apply(lambda x: x.question+'_'+x.answer))

dfout = (dfout.to_frame()[0].str.get_dummies()
          .reset_index(-1,drop=True)
          .groupby(level=[0,1,2]).sum())

中间输出:

                    question_1_answer1  question_1_answer3  \
user_id age gender                                           
1       34  male                     0                   1   
2       22  female                   1                   1   
                    question_1_answer5  question_2_answer1  question_2_answer4  
user_id age gender                                                              
1       34  male                     1                   1                   1  
2       22  female                   0                   0                   0 

清理:

dfout.columns = dfout.columns.str.replace('question_','q')
dfout.columns = dfout.columns.str.replace('answer','ans')
dfout.reset_index(inplace=True)

print(dfout)

输出:

   user_id  age  gender  q1_ans1  q1_ans3  q1_ans5  q2_ans1  q2_ans4
0        1   34    male        0        1        1        1        1
1        2   22  female        1        1        0        0        0

编辑新的可能更快的代码:

df_1 = df.set_index(['user_id','age','gender'])

df_1['Q_Ans'] = df_1['question'].str.replace('question_','q') + '_' +df_1['answer'].str.replace('answer','ans')

df_1['Q_Ans'].str.get_dummies().groupby(level=[0,1,2]).sum().reset_index()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM