分割数据框,将所有值都放在一行中

时间:2020-10-17 21:06:24

标签: python pandas dataframe

我得到了以下数据帧,它是动态创建的,但是将所有相关值保存到一行:

df

+----------------+----------------+----------------+----------------+
|       1        |       2        |       3        |       4        |
+----------------+----------------+----------------+----------------+
| a1, b1, c1, d1 | a2, b2, c2, d2 | a3, b3, c3, d3 | a4, b4, c4, d4 |
+----------------+----------------+----------------+----------------+

我需要将所有a_i值都放在一行中,所有b都这样,以此类推(列已定义并且是常数):

+----+----+----+----+
| 1  | 2  | 3  | 4  |
+----+----+----+----+
| a1 | a2 | a3 | a4 |
| b1 | b2 | b3 | b4 |
| c1 | c2 | c3 | c4 |
| d1 | d2 | d3 | d4 |
+----+----+----+----+

由于情况下 df 中不同字母的数量在变化,我需要一个动态的解决方案将 df 转换为上面的形式。

4 个答案:

答案 0 :(得分:6)

给出以下结构的df:

df = pd.DataFrame({1:[np.array('a1 b1 c1 d1'.split(' '))],
                  2:[np.array('a2 b2 c2 d2'.split(' '))],
                  3:[np.array('a3 b3 c3 d3'.split(' '))],
                  4:[np.array('a4 b4 c4 d4'.split(' '))]})

输入数据框:

                  1                 2                 3                 4
0  [a1, b1, c1, d1]  [a2, b2, c2, d2]  [a3, b3, c3, d3]  [a4, b4, c4, d4]

您可以使用pd.Series.explode:

df.apply(pd.Series.explode)

输出:

    1   2   3   4
0  a1  a2  a3  a4
0  b1  b2  b3  b4
0  c1  c2  c3  c4
0  d1  d2  d3  d4

答案 1 :(得分:5)

有点类似于斯科特·波士顿(Scott Boston)的答案,但速度更快(apply出奇地慢):

pd.DataFrame(df.values[0].tolist(), columns=df.columns)
#    1   2   3   4
#0  a1  b1  c1  d1
#1  a2  b2  c2  d2
#2  a3  b3  c3  d3
#3  a4  b4  c4  d4

答案 2 :(得分:1)

部分原始答案: 如果您的列仅在一帧中包含一个由长逗号分隔的字符串,则为:

df = pd.DataFrame(
    [
        ",".join(["a" + str(i) for i in range(4)]),
        ",".join(["b" + str(i) for i in range(4)]),
    ],      
).T
df.columns = list("ab")
df.apply(lambda x: pd.Series(x[0].split(',')))

其他内容: (这是基于已经解决了该问题的其他答案,但是对于执行效率有一个清晰的认识,尽管可以在此处进行测试和打印,但它很有帮助...我感到很惊讶,基于结果,我将编写相同的内容功能和将来更好的性能:致谢@DIZ和@Scott Boston)

import pandas as pd
import numpy as np

df = pd.DataFrame({i: [np.array([x + str(i) for x in ['a','b','c','d']])] for i in range(1,5)})

def convert_using_explode(my_df):
    return my_df.apply(pd.Series.explode)

def convert_using_conversion_to_list(my_df):
    return pd.DataFrame(my_df.values[0].tolist(), columns=my_df.columns)

# this is what I would have most probably done before getting involved in this question
def convert_first_idx_to_series(my_df):
    another_df = pd.DataFrame()
    for col in my_df:
        another_df[col] = pd.Series(my_df.loc[0, col])
    return another_df

现在定时执行:

%time convert_using_explode(df)
Wall time: 2 ms
Out[10]: 
    1   2   3   4
0  a1  a2  a3  a4
0  b1  b2  b3  b4
0  c1  c2  c3  c4
0  d1  d2  d3  d4

%time convert_using_conversion_to_list(df)
Wall time: 966 µs
Out[11]: 
    1   2   3   4
0  a1  b1  c1  d1
1  a2  b2  c2  d2
2  a3  b3  c3  d3
3  a4  b4  c4  d4

%time convert_first_idx_to_series(df)
Wall time: 1.99 ms
Out[61]: 
    1   2   3   4
0  a1  a2  a3  a4
1  b1  b2  b3  b4
2  c1  c2  c3  c4
3  d1  d2  d3  d4

请注意@DIZ版本的运行速度是其余版本的两倍。

答案 3 :(得分:1)

动态解决方案

import pandas as pd
import numpy as np

N = 6


df = pd.Series(
    {
        n: np.array([f"{chr(ord('a') + ci)}{n}" for ci in range(N)])
        for n in range(1, N + 1)
    }
).to_frame().T

pd.concat([df[i].explode() for i in range(1, N + 1)], axis=1)
    1   2   3   4   5   6
0   a1  a2  a3  a4  a5  a6
0   b1  b2  b3  b4  b5  b6
0   c1  c2  c3  c4  c5  c6
0   d1  d2  d3  d4  d5  d6
0   e1  e2  e3  e4  e5  e6
0   f1  f2  f3  f4  f5  f6