将 pandas 列的值转换为行

7
我正在尝试将数据框转换为长格式。
我要开始使用的数据框:
df = pd.DataFrame([['a', 'b'],
                   ['d', 'e'], 
                   ['f', 'g', 'h'],
                   ['q', 'r', 'e', 't']])
df = df.rename(columns={0: "Key"})

    Key 1   2   3
0   a   b   None    None
1   d   e   None    None
2   f   g   h       None
3   q   r   e       t

列数未指定,可能超过4列。每个键值对后面应该有一个新行。
这样可以获得我需要的内容,但似乎应该有一种方法可以在不必删除空值的情况下完成此操作。
new_df = pd.melt(df, id_vars=['Key'])[['Key', 'value']]
new_df = new_df.dropna()


    Key value
0   a   b
1   d   e
2   f   g
3   q   r
6   f   h
7   q   e
11  q   t​

1
嘿!你是为了性能还是内存原因而避免使用dropna函数? - cs95
1
@cᴏʟᴅsᴘᴇᴇᴅ 说实话,昨晚我在疲惫的情况下做这件事时感觉有点像黑客,因为我担心以后会遇到意外的行为。现在考虑一下,并根据答案,似乎应该没问题了,尽管下面的解决方案也非常好。 - johnchase
3个回答

5

选项1
你可以通过使用set_index + stack来完成此操作:

df.set_index('Key').stack().reset_index(level=0, name='value').reset_index(drop=True)

  Key value
0   a     b
1   d     e
2   f     g
3   f     h
4   q     r
5   q     s
6   q     t

如果您不想保持重置索引,则可以使用一个中间变量并创建新的数据框:

v = df.set_index('Key').stack()
pd.DataFrame({'Key' : v.index.get_level_values(0), 'value' : v.values})

  Key value
0   a     b
1   d     e
2   f     g
3   f     h
4   q     r
5   q     s
6   q     t

这里的关键是默认情况下 stack 会自动去除 NaN (您可以通过设置 dropna=False 来禁用此功能)。
选项2
使用np.repeat和numpy版本的 pd.DataFrame.stack 可以获得更高的性能。
i = df.pop('Key').values
j = df.values.ravel()

pd.DataFrame({'Key' : v.repeat(df.count(axis=1)), 'value' : j[pd.notnull(j)]
})

  Key value
0   a     b
1   d     e
2   f     g
3   f     h
4   q     r
5   q     s
6   q     t

5

通过使用 melt(我认为在这里不会产生更多的麻烦,dropna 也不需要)

df.melt('Key').dropna().drop('variable',1)
Out[809]: 
   Key value
0    a     b
1    d     e
2    f     g
3    q     r
6    f     h
7    q     s
11   q     t

如果没有使用 dropna

s=df.fillna('').set_index('Key').sum(1).apply(list)
pd.DataFrame({'Key': s.reindex(s.index.repeat(s.str.len())).index,'value':s.sum()})


Out[862]: 
  Key value
0   a     b
1   d     e
2   f     g
3   f     h
4   q     r
5   q     s
6   q     t

请注意,这是 OP 的解决方案,但是...应该有一种方法可以在不必放弃空值的情况下完成此操作。 - cs95

2

通过理解
这假定关键字是行的第一个元素。

pd.DataFrame(
    [[k, v] for k, *r in df.values for v in r if pd.notna(v)],
    columns=['Key', 'value']
)

  Key value
0   a     b
1   d     e
2   f     g
3   f     h
4   q     r
5   q     s
6   q     t

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接