【问题标题】:Reshaping pandas DataFrame Python 3.x重塑 pandas DataFrame Python 3.x
【发布时间】:2019-01-14 07:30:14
【问题描述】:

我有一个这样的熊猫:

df =
cid    pid     purl    tid   turl     sid   surl
c1      p1     urlp1   t1    urlt1    s1    urls1
c1      p1     urlp1   t1    urlt1    s2    urls2
c1      p1     urlp1   t1    urlt1    s3    urls3
c2      p2     urlp2   t2    urlt2    s5    urls5
c2      p2     urlp2   t2    urlt2    s6    urls6

我想要的是这样的结果:

cid     uid      url
c1      p1      urlp1 
c1      t1      urlt1
c1      s1      urls1   
c1      s2      urls2
c1      s3      urls3
c2      p2      urlp2   
c2      t2      urlt2
c2      s5      urls5
c2      s6      urls6

我尝试使用pd.melt 来实现这一点,但我只能部分这样做:

df2 = pd.melt(df, id_vars = 'cid', value_vars = ['pid','tid','purl'], value_name = 'userid')

如何获得更多列?我需要更多 value_name 的列吗?我怎样才能做到这一点?

【问题讨论】:

  • 您可以使用这些列将第一个数据框拆分为三个数据框。 [cid, pid, urlp][cid, tid, urlt]['cid, sid, urls']。拆分后,您可以使用 cid 将所有这些合并到一个数据框中。

标签: python pandas


【解决方案1】:

一种手动​​解决方案是使用列表推导式。步骤是:

  1. 将索引设置为键列cid
  2. 根据列数计算列表理解循环的长度。
  3. concat 与您的数据框列表一起使用,并通过pipe 重命名列[如果需要,添加其他格式]。
  4. 最后,reset_index(将索引提升为系列)和drop_duplicates

这是一个演示:

df = df.set_index('cid')

def formatter(df):
    df.columns = ['uid', 'url']
    return df

n = int(len(df.columns) / 2)
L = [df.iloc[:, 2*i:2*(i+1)].pipe(formatter) for i in range(n)]
res = pd.concat(L, axis=0).reset_index().drop_duplicates()

print(res)

   cid uid    url
0   c1  p1  urlp1
3   c2  p2  urlp2
5   c1  t1  urlt1
8   c2  t2  urlt2
10  c1  s1  urls1
11  c1  s2  urls2
12  c1  s3  urls3
13  c2  s5  urls5
14  c2  s6  urls6

【讨论】:

    【解决方案2】:

    不确定这是最直接的方法,但这是我能想到的:

    import pandas as pd
    from io import StringIO
    
    s = """cid    pid     purl    tid   turl     sid   surl
    c1      p1     urlp1   t1    urlt1    s1    urls1
    c1      p1     urlp1   t1    urlt1    s2    urls2
    c1      p1     urlp1   t1    urlt1    s3    urls3
    c2      p2     urlp2   t2    urlt2    s5    urls5
    c2      p2     urlp2   t2    urlt2    s6    urls6"""
    
    df = pd.read_table(StringIO(s), sep='\\s+', header=0)
    df2 = df.set_index('cid')
    df3 = pd.concat([df2[['pid', 'purl']].rename(columns={'pid': 'uid', 'purl': 'url'}),
                     df2[['tid', 'turl']].rename(columns={'tid': 'uid', 'turl': 'url'}),
                     df2[['sid', 'surl']].rename(columns={'sid': 'uid', 'surl': 'url'})],
                    axis=0)
    result = df3.drop_duplicates().sort_index().reset_index()
    print(result)
    

    输出:

      cid uid    url
    0  c1  p1  urlp1
    1  c1  t1  urlt1
    2  c1  s1  urls1
    3  c1  s2  urls2
    4  c1  s3  urls3
    5  c2  p2  urlp2
    6  c2  t2  urlt2
    7  c2  s5  urls5
    8  c2  s6  urls6
    

    【讨论】:

    • 非常感谢大家,两个答案都是正确的。我认为第一个实际上是一个更好的解决方案,因此被接受。
    • @KaranGupta 是的 jpp 的答案更简洁,更具可扩展性。
    【解决方案3】:

    这些列有一个模式 -> 有些以id 结尾,有些以url 结尾。

    我们可以使用这种模式来重塑数据,并删除重复数据。

    这只是一种替代方法,它依赖于pyjanitor 中的pivot_longer 来帮助进行重塑过程:

    # pip install pyjanitor
    import pandas as pd
    import janitor as jn
    (df.pivot_longer(index = 'cid', 
                     names_to = ('uid', 'url'), 
                     names_pattern = (r".+id", r".+url"), 
                     sort_by_appearance = True)
       .drop_duplicates(ignore_index = True)
    )
      cid uid    url
    0  c1  p1  urlp1
    1  c1  t1  urlt1
    2  c1  s1  urls1
    3  c1  s2  urls2
    4  c1  s3  urls3
    5  c2  p2  urlp2
    6  c2  t2  urlt2
    7  c2  s5  urls5
    8  c2  s6  urls6
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-12
      • 2017-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-22
      相关资源
      最近更新 更多