【问题标题】:Pandas Dataframe: split column into multiple columnsPandas Dataframe:将列拆分为多列
【发布时间】:2020-05-09 23:20:36
【问题描述】:

我需要为一个可以有多个值的分类数据字段打破目前收集多个值(不幸的是其他人的 excel 表)的 DataFrame 中的一列。

正如您在下面看到的,列标题中有 15 个类别代码。

Original DataFrame

我想根据列标题['Pamphlet'] 中看到的类别代码拆分列,然后转换为原始列中的每条记录收集的值以映射到相应的新列作为 (1) 进行检查(0) 表示未选中,而不是原始值 [1,2,4,5]

这是基于 , 在值之间进行拆分的代码,但我需要将它们放入我需要设置的新列中,方法是将列 ['Pamphlet'] 拆分为标题 [15: 1) OSA\n2) Nutrition\n3) Activity\n4) 等中的值。]。

'''df_old['Pamphlets'].str.split(pat = ',', n = -1, expand = True)'''

Shape of desired DatFrame

如果我能大致了解什么是最好的方法,甚至可以在 Pandas 中做到这一点,谢谢。

【问题讨论】:

标签: pandas split


【解决方案1】:

您需要一一浏览您的列并划分标题,然后为由拆分列组成的每一列创建一个新数据框,然后将所有这些连接回原始数据框。这有点混乱但可行。

您需要使用一个函数和一些循环来遍历这些列。

首先让我们定义数据框。 (如果您在以后的问题中提供可复制的数据框和任何其他数据,将不胜感激。

data = {
    "1) Mail\n2) Email \n3) At PAC/TPAC": [2, 1, 3, 2, 3, 1, 3, 2, 3, 1],
    "1) ACC\n2) IM \n3) PT\n4) Smoking, \n5) Cessation": [5, 1, 4, 4, 2, 5, 1, 4, 3, 2],
}
df_full = pd.DataFrame(data)
print(df_full)

 1) Mail\n2) Email \n3) At PAC/TPAC  1) ACC\n2) IM \n3) PT\n4) Smoking, \n5) Cessation
0                                   2                                                  5
1                                   1                                                  1
2                                   3                                                  4
3                                   2                                                  4
4                                   3                                                  2
5                                   1                                                  5
6                                   3                                                  1
7                                   2                                                  4
8                                   3                                                  3
9                                   1                                                  2

我们将使用函数逐列遍历数据框。现在让我们为第一列手动构建列。在我们将下一部分变成一个函数之后。

首先,让我们抓取第一列。

s_col = df_full.iloc[:, 0]
print(s_col)

0    2
1    1
2    3
3    2
4    3
5    1
6    3
7    2
8    3
9    1
Name: 1) Mail\n2) Email \n3) At PAC/TPAC, dtype: int64

将标题拆分成单独的部分。

col = s_col.name.split("\n")
print(col)
['1) Mail', '2) Email ', '3) At PAC/TPAC']

清除所有前导或尾随空格。

col = [x.strip() for x in col]
print(col)
['1) Mail', '2) Email', '3) At PAC/TPAC']

从系列和列标题创建一个新的数据框。

data = {col[x]: s_col.to_list() for x in range(len(col))}
df = pd.DataFrame(data)
print(df)
  1) Mail  2) Email  3) At PAC/TPAC
0        2         2               2
1        1         1               1
2        3         3               3
3        2         2               2
4        3         3               3
5        1         1               1
6        3         3               3
7        2         2               2
8        3         3               3
9        1         1               1

创建一个副本以更改值。

df_res = df.copy()

遍历列标题,获取第一个数字,然后过滤并应用 bool。

for col in df.columns:
    value = pd.to_numeric(col[0])
    df_res.loc[df[col] == value, col] = 1
    df_res.loc[df[col] != value, col] = 0

print(df_res)
  1) Mail  2) Email  3) At PAC/TPAC
0        0         1               0
1        1         0               0
2        0         0               1
3        0         1               0
4        0         0               1
5        1         0               0
6        0         0               1
7        0         1               0
8        0         0               1
9        1         0               0

现在我们已经将一列拆分为其组件并分配了一个布尔值。

让我们退后一步,将上面的函数变成一个函数,这样我们就可以将它用于原始数据框中的每一列。

def split_column(s_col):
    # Split the header into individual pieces.
    col = s_col.name.split("\n")

    # Clean up any leading or trailing white space.
    col = [x.strip() for x in col]

    # Create a new dataframe from series and column heads.
    data = {col[x]: s_col.to_list() for x in range(len(col))}
    df = pd.DataFrame(data)

    # Create a copy to make changes to the values.
    df_res = df.copy()

    # Go through the column headers, get the first number, then filter and apply bool.
    for col in df.columns:
        value = pd.to_numeric(col[0])
        df_res.loc[df[col] == value, col] = 1
        df_res.loc[df[col] != value, col] = 0

    return df_res

现在是最后一步。让我们创建一个循环来遍历原始数据框中的列,调用函数来拆分每一列,然后将其连接到原始数据框中减去拆分的列。

for c in df_full.columns:
    # Call the function to get the split columns in a new dataframe.
    df_split = split_column(df_full[c])

    # Join it with the origianl full dataframe but drop the current column.
    df_full = pd.concat([df_full.loc[:, ~df_full.columns.isin([c])], df_split], axis=1)

print(df_full)
   1) Mail  2) Email  3) At PAC/TPAC  1) ACC  2) IM  3) PT  4) Smoking,  5) Cessation
0        0         1               0       0      0      0            0             1
1        1         0               0       1      0      0            0             0
2        0         0               1       0      0      0            1             0
3        0         1               0       0      0      0            1             0
4        0         0               1       0      1      0            0             0
5        1         0               0       0      0      0            0             1
6        0         0               1       1      0      0            0             0
7        0         1               0       0      0      0            1             0
8        0         0               1       0      0      1            0             0
9        1         0               0       0      1      0            0             0

这里是完整的代码...

data = {
    "1) Mail\n2) Email \n3) At PAC/TPAC": [2, 1, 3, 2, 3, 1, 3, 2, 3, 1],
    "1) ACC\n2) IM \n3) PT\n4) Smoking, \n5) Cessation": [5, 1, 4, 4, 2, 5, 1, 4, 3, 2],
}
df_full = pd.DataFrame(data)


def split_column(s_col):
    # Split the header into individual pieces.
    col = s_col.name.split("\n")

    # Clean up any leading or trailing white space.
    col = [x.strip() for x in col]

    # Create a new dataframe from series and column heads.
    data = {col[x]: s_col.to_list() for x in range(len(col))}
    df = pd.DataFrame(data)

    # Create a copy to make changes to the values.
    df_res = df.copy()

    # Go through the column headers, get the first number, then filter and apply bool.
    for col in df.columns:
        value = pd.to_numeric(col[0])
        df_res.loc[df[col] == value, col] = 1
        df_res.loc[df[col] != value, col] = 0

    return df_res


for c in df_full.columns:
    # Call the function to get the split columns in a new dataframe.
    df_split = split_column(df_full[c])

    # Join it with the origianl full dataframe but drop the current column.
    df_full = pd.concat([df_full.loc[:, ~df_full.columns.isin([c])], df_split], axis=1)

print(df_full)

【讨论】:

  • 感谢您的详尽解释,我将提供原始的可复制数据框。我是使用 pandas 和 python 的新手,所以我对与 pandas 对象关联的方法和属性有很好的基础,但我还不太擅长使用循环来迭代许多数据结构,但感谢这个很好的例子。为我节省了大量的体力劳动。
  • 只是 pandas 的一般思维方式。如果你在循环,你很可能做错了。当然,这是一个粗略的概括,循环/迭代行有很多应用程序。但是,当您第一次开始时,请尽可能尝试找到矢量化的解决方案,并摆脱编程的传统思维方式。矢量化非常快速高效。祝你好运。
  • 是的,当我试图解决这个问题时,我一直在考虑矢量化,因为这种方法是在 pandas 中引入的。感谢您的帮助,它是一个非常棒的库,它只是处理许多使用 excel 遗留下来的项目,但现在正在转向使用 Web 应用程序来进行主要数据收集,因此 pandas 确实有助于工作使用这些现有数据。
猜你喜欢
  • 2016-11-17
  • 1970-01-01
  • 1970-01-01
  • 2018-05-28
  • 2022-12-29
  • 1970-01-01
  • 1970-01-01
  • 2019-05-18
  • 2022-01-03
相关资源
最近更新 更多