熊猫长期以来通过两个变量进行广泛重塑

Luk*_*uke 30 python reshape pandas

我有长格式的数据,我试图重塑到宽,但似乎没有一个直接的方法来使用融化/堆栈/取消堆栈:

Salesman  Height   product      price
  Knut      6        bat          5
  Knut      6        ball         1
  Knut      6        wand         3
  Steve     5        pen          2
Run Code Online (Sandbox Code Playgroud)

变为:

Salesman  Height    product_1  price_1  product_2 price_2 product_3 price_3  
  Knut      6        bat          5       ball      1        wand      3
  Steve     5        pen          2        NA       NA        NA       NA
Run Code Online (Sandbox Code Playgroud)

我认为Stata可以使用reshape命令执行类似的操作.

Kar*_* D. 34

一个简单的支点可能足以满足您的需求,但这是我为重现您想要的输出而做的事情:

df['idx'] = df.groupby('Salesman').cumcount()
Run Code Online (Sandbox Code Playgroud)

只需添加一个组内计数器/索引就可以获得大部分内容,但列标签将不是您想要的:

print df.pivot(index='Salesman',columns='idx')[['product','price']]

        product              price        
idx            0     1     2      0   1   2
Salesman                                   
Knut         bat  ball  wand      5   1   3
Steve        pen   NaN   NaN      2 NaN NaN
Run Code Online (Sandbox Code Playgroud)

为了更接近您想要的输出,我添加了以下内容:

df['prod_idx'] = 'product_' + df.idx.astype(str)
df['prc_idx'] = 'price_' + df.idx.astype(str)

product = df.pivot(index='Salesman',columns='prod_idx',values='product')
prc = df.pivot(index='Salesman',columns='prc_idx',values='price')

reshape = pd.concat([product,prc],axis=1)
reshape['Height'] = df.set_index('Salesman')['Height'].drop_duplicates()
print reshape

         product_0 product_1 product_2  price_0  price_1  price_2  Height
Salesman                                                                 
Knut           bat      ball      wand        5        1        3       6
Steve          pen       NaN       NaN        2      NaN      NaN       5
Run Code Online (Sandbox Code Playgroud)

编辑:如果你想把程序推广到更多的变量我认为你可以做类似下面的事情(虽然它可能不够有效):

df['idx'] = df.groupby('Salesman').cumcount()

tmp = []
for var in ['product','price']:
    df['tmp_idx'] = var + '_' + df.idx.astype(str)
    tmp.append(df.pivot(index='Salesman',columns='tmp_idx',values=var))

reshape = pd.concat(tmp,axis=1)
Run Code Online (Sandbox Code Playgroud)

@Luke说:

我认为Stata可以使用reshape命令执行类似的操作.

你可以,但我认为你还需要一个内部组计数器来获得stata中的重塑以获得所需的输出:

     +-------------------------------------------+
     | salesman   idx   height   product   price |
     |-------------------------------------------|
  1. |     Knut     0        6       bat       5 |
  2. |     Knut     1        6      ball       1 |
  3. |     Knut     2        6      wand       3 |
  4. |    Steve     0        5       pen       2 |
     +-------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

如果你添加,idx那么你可以重塑stata:

reshape wide product price, i(salesman) j(idx)
Run Code Online (Sandbox Code Playgroud)

  • 效果很好.这对熊猫来说是一个很好的功能.已经很宽,为什么不是另一个方向. (7认同)

ALo*_*llz 18

Karl D 的解决方案是问题的核心。但是我发现旋转所有内容(.pivot_table因为有两个索引列)然后sort分配列来折叠要容易得多MultiIndex

df['idx'] = df.groupby('Salesman').cumcount()+1
df = df.pivot_table(index=['Salesman', 'Height'], columns='idx', 
                    values=['product', 'price'], aggfunc='first')

df = df.sort_index(axis=1, level=1)
df.columns = [f'{x}_{y}' for x,y in df.columns]
df = df.reset_index()
Run Code Online (Sandbox Code Playgroud)

输出:

  Salesman  Height  price_1 product_1  price_2 product_2  price_3 product_3
0     Knut       6      5.0       bat      1.0      ball      3.0      wand
1    Steve       5      2.0       pen      NaN       NaN      NaN       NaN
Run Code Online (Sandbox Code Playgroud)

  • 太感谢了。尽管我的数据框中已经有了 idx col,但您的解决方案能够将重复测量从长格式变为宽格式。Pandas 有 [wide_to_long()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.wide_to_long.html) 的功能,但不提供 long_to_wide 的功能。伤心。 (2认同)

Gec*_*cko 17

有点旧,但我会发布给其他人.

你想要的是什么,但你可能不应该想要它;)Pandas支持行和列的层次索引.在Python 2.7.x中......

from StringIO import StringIO

raw = '''Salesman  Height   product      price
  Knut      6        bat          5
  Knut      6        ball         1
  Knut      6        wand         3
  Steve     5        pen          2'''
dff = pd.read_csv(StringIO(raw), sep='\s+')

print dff.set_index(['Salesman', 'Height', 'product']).unstack('product')
Run Code Online (Sandbox Code Playgroud)

产生比您正在寻找的更方便的表示

                price             
product          ball bat pen wand
Salesman Height                   
Knut     6          1   5 NaN    3
Steve    5        NaN NaN   2  NaN
Run Code Online (Sandbox Code Playgroud)

使用set_index和unstacking与单个函数作为pivot的优点是,您可以将操作分解为明确的小步骤,从而简化调试.

  • 为什么你还在使用 Python 2.7?在 Python 3 中怎么样? (2认同)

小智 10

pivoted = df.pivot('salesman', 'product', 'price')
Run Code Online (Sandbox Code Playgroud)

皮克.192 Python for Data Analysis

  • 当使用这个方法(从书中)我得到"ValueError:索引包含重复的条目,无法重塑"即使我使用了df.drop_duplicates() (5认同)

Cha*_*ton 10

这是另一个更加充实的解决方案,取自Chris Albon的网站.

创建"长"数据帧

raw_data = {'patient': [1, 1, 1, 2, 2],
                'obs': [1, 2, 3, 1, 2],
          'treatment': [0, 1, 0, 1, 0],
              'score': [6252, 24243, 2345, 2342, 23525]}

df = pd.DataFrame(raw_data, columns = ['patient', 'obs', 'treatment', 'score'])
Run Code Online (Sandbox Code Playgroud)

制作"广泛"的数据

df.pivot(index='patient', columns='obs', values='score')
Run Code Online (Sandbox Code Playgroud)


sam*_*mmy 5

一个老问题;这是对已经很好的答案的补充。pyjanitor中的hub_wider作为从长到宽重塑的抽象可能会有所帮助(它是 pd.pivot 的包装器):

# pip install pyjanitor
import pandas as pd
import janitor

idx = df.groupby(['Salesman', 'Height']).cumcount().add(1)

(df.assign(idx = idx)
   .pivot_wider(index = ['Salesman', 'Height'], names_from = 'idx')
)
 
  Salesman  Height product_1 product_2 product_3  price_1  price_2  price_3
0     Knut       6       bat      ball      wand      5.0      1.0      3.0
1    Steve       5       pen       NaN       NaN      2.0      NaN      NaN

Run Code Online (Sandbox Code Playgroud)