如何从多列构建索引并设置为列pandas数据框?

时间:2017-01-07 09:28:55

标签: python pandas unique

我想学习如何将数据框列作为来自多列的代码。

在下面的部分示例中,我尝试了路径中可能是一种笨拙的方式:将唯一值作为临时数据框;将一些前缀字符串连接到临时行号作为新列,它们连接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获得以下结果的聪明的pythonic方法是什么?

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

感谢。

在答案之后,作为一个练习,我一直在研究非pythonic版本,我想到的是我从很好的答案得到的见解,并达成了这个:

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了。谢谢大家。

4 个答案:

答案 0 :(得分: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

如果需要指定输出列code的位置insertnumpy.where缺失值,请使用fillna。最后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

答案 1 :(得分:2)

  

如何将'temp'行号及其值输入tmp列?

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

索引保留在索引列中,如果要将其明确复制到数据列中,只需执行tmp['index'] = tmp.index

  

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

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

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,如果您对大型数据集进行操作,这可能会很重要。

答案 2 :(得分:2)

使用groupbydf.index

['col1', 'col2'] transform('first')上的{p> 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)

答案 3 :(得分:0)

如果您拥有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构成的多索引的数据框:

enter image description here

访问多重数据框

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