【问题标题】:How to build index from multiple columns and set to a column pandas data frame?如何从多列构建索引并设置为列熊猫数据框?
【发布时间】:2017-01-07 09:28:55
【问题描述】:

我想学习如何将数据框列作为从多个列映射的代码。

在下面的部分示例中,我尝试了一种可能是笨拙的方法:获取唯一值作为临时数据框;将一些前缀字符串连接到临时行号作为新列,然后它们加入 2 个数据框。

df = pd.DataFrame({'col1' : ['A1', 'A2', 'A1', 'A3'],
                   'col2' : ['B1', 'B2', 'B1', 'B1'],
                   'value' : [100, 200, 300, 400],
                   })

tmp = df[['col1','col2']].drop_duplicates(['col1', 'col2'])


#   col1 col2
# 0   A1   B1
# 1   A2   B2
# 3   A3   B1

第一个问题是如何获取 'temp' 行号及其值到 tmp 列?

从 df 获得以下结果的聪明的 Python 方法是什么?

dfnew = pd.DataFrame({'col1' : ['A1', 'A2', 'A1', 'A3'],
                   'col2' : ['B1', 'B2', 'B1', 'B1'],
                   'code' :  ['CODE0','CODE1', 'CODE0', 'CODE3'],
                   'value' : [100, 200, 300, 400],
                   })

    code col1 col2  value
0  CODE0   A1   B1    100
1  CODE1   A2   B2    200
2  CODE0   A1   B1    300
3  CODE3   A3   B1    400

谢谢。

在得到答案之后,作为一个练习,我继续研究我想到的非 Python 版本,并从出色的答案中获得了见解,并达到了这一点:

tmp = df[['col1','col2']].drop_duplicates(['col1', 'col2'])

tmp.reset_index(inplace=True)

tmp.drop('index', axis=1, inplace=True)

tmp['code'] = tmp.index.to_series().apply(lambda x: 'code' + format(x, '04d'))

dfnew = pd.merge(df, tmp, on=['col1', 'col2'])

在发布此问题时,我没有意识到将索引重置为具有新序列而不是原始索引号会更好。

我尝试了一些变体,但我不知道如何在一个命令中链接“reset_index”和“drop”。

我开始喜欢 Python。谢谢大家。

【问题讨论】:

    标签: python pandas unique


    【解决方案1】:

    groupby df.index['col1', 'col2'] 使用 transform('first')map

    df.assign(
        code=df.index.to_series().groupby(
            [df.col1, df.col2]
        ).transform('first').map('CODE{}'.format)
    )[['code'] + df.columns.tolist()]
    
        code col1 col2  value
    0  CODE0   A1   B1    100
    1  CODE1   A2   B2    200
    2  CODE0   A1   B1    300
    3  CODE3   A3   B1    400
    

    解释

    # turn index to series so I can perform a groupby on it
    idx_series = df.index.to_series()
    
    # groupby col1 and col2 to establish uniqueness
    idx_gb = idx_series.groupby([df.col1, df.col2])
    
    # get first index value in each unique group
    # and broadcast over entire group with transform
    idx_tf = idx_gb.transform('first')
    
    # map a format function to get desired string
    code = idx_tf.map('code{}'.format)
    
    # use assign to create new column
    df.assign(code=code)
    

    【讨论】:

    • 嗨@piRSquared,谢谢,确实非常快速的解决方案。额外的帮助?,我怎么能设置'groupby([df.col1,df.col2]'在列/字段的变量列表上完成?类似于'df.groupby [[字段列表/系列]]'。我想将它概括为一个以字段名称为基础以代码为参数的函数。
    【解决方案2】:

    您可以先sort_valuescol1col2 其中duplicated 查找所有重复项:

    df = df.sort_values(['col1', 'col2'])
    mask = df.duplicated(['col1','col2'])
    print (mask)
    0    False
    2     True
    1    False
    3    False
    dtype: bool
    

    然后使用insert 如果需要指定输出列的位置codenumpy.wherefillna 缺失值。最后sort_index

    df.insert(0, 'code', np.where(mask, np.nan, 'CODE' + df.index.astype(str)))
    df.code = df.code.ffill()
    df = df.sort_index()
    print (df)
        code col1 col2  value
    0  CODE0   A1   B1    100
    1  CODE1   A2   B2    200
    2  CODE0   A1   B1    300
    3  CODE3   A3   B1    400
    

    【讨论】:

    • 当然,顺便说一句,我认为我的代码更快,你可以检查一下。 ;)
    • 好的,我将尝试在此处与真实数据框进行比较测试。谢谢。
    • 告诉我,我真的很感兴趣。因为显然groupby 很慢。
    • 你的解决方案是我在这里做的一些测试中第二快的。我将我的数据与 aprox 一起使用。 150.000 条记录,当我在最后删除排序时,它非常接近 piRSquared 解决方案。这真的有必要吗? concat 解决方案是最慢的。
    • 不,最后的 sort_index 不是必需的,只有更好的输出;)
    【解决方案3】:

    如何获取 'temp' 行号及其值到 tmp 列?

    值列未传播,因为您在开头将其过滤掉:df[['col1','col2']]。因此,通过将其更改为 tmp = df.drop_duplicates(['col1', 'col2']) 来解决此问题。

    索引保存在索引列中,如果要显式复制到数据列中,只需执行tmp['index'] = tmp.index即可。

    从 df 获得以下结果的巧妙 Python 方法是什么?

    我不知道它是否特别聪明,因为这是主观的,但实现它的一种方法是

    pd.concat([gr.assign(code='CODE{}'.format(min(gr.index))) for _, gr in df.groupby(['col1', 'col2'])])
    

    最后,要以您指定的形式获得结果,您可以在上面添加.sort_index()[['code', 'col1', 'col2', 'value']],以指定列的顺序。给予:

    newdf = pd.concat([gr.assign(code='CODE{}'.format(min(gr.index))) for _, gr in df.groupby(['col1', 'col2'])]).sort_index()[['code', 'col1', 'col2', 'value']]
    

    可能的性能瓶颈可能是groupbyconcat,如果您对大型数据集进行操作,这可能很重要。

    【讨论】:

      【解决方案4】:

      如果你有这样的df DataFrame:

          state       year    population
      0   California  2000    33871648
      1   California  2010    37253956
      2   New York    2000    18976457
      3   New York    2010    19378102
      4   Texas       2000    20851820
      5   Texas       2010    25145561
      

      您可以从 stateyear 列创建索引:

      df2 = df.set_index(['state','year'])
      

      这将为您提供由 stateyear 列构造的多索引数据框:

      访问多索引数据帧

      df['California',2000]
      Result: 33871648
      
      df[:,2010]
      Result:
      state
      California    37253956
      New York      19378102
      Texas         25145561
      dtype: int64
      
      
      pop.loc['California':'New York']
      Result:
      state       year
      California  2000    33871648
                  2010    37253956
      New York    2000    18976457
                  2010    19378102
      dtype: int64
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-16
        • 1970-01-01
        • 1970-01-01
        • 2021-12-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多