/ / Pandas: Розділити багатозначні стовпці на основі роздільників в назві - python, pandas, split

Панди: розділені багатозначні стовпці на основі іменних обмежувачів - python, pandas, split

У мене є великий файл даних Pandas, де єкількість багатозначних стовпців. Ці стовпці мають "/" у своїх іменах, а значення в цих стовпцях також розділені "/". Нижче наведено мінімальний репрезентативний приклад такого кадру даних.

        Name   North / South   East / West   No1 / No2 / No3
0        ABC           0 / 1         0 / 0        10 / 3 / 6
1        XYZ           1 / 0         0 / 1         4 / 5 / 6
2        PQR           1 / 0         0 / 1         3 / 6 / 6

Я хотів би розділити колонки. Простим способом є створення нового стовпця, а потім ітерація по довжині індексу, заповнюючи його розбитою рядком вздовж кожного елемента. Але мені доведеться його жорстко зафіксувати для всіх багатозначних стовпців.

Чи є більш загальний спосіб зробити це? Можливо, скануйте через df.columns, якщо елемент містить "/" в ньому, запустіть іншу функцію, щоб розбити цей стовпець? Для наведеного вище кадру даних бажаний вихідний результат полягає в наступному.

        Name  North  South  East  West  No1  No2  No3
0        ABC      0      1     0     0   10    3    6
1        XYZ      1      0     0     1    4    5    6
2        PQR      1      0     0     1    3    6    6

Відповіді:

0 для відповіді № 1
#get columns not contains / and set index
cols = df.columns[~df.columns.str.contains("/")].tolist()
df = df.set_index(cols)
print (df)
North / South East / West No1 / No2 / No3
Name
ABC          0 / 1       0 / 0      10 / 3 / 6
XYZ          1 / 0       0 / 1       4 / 5 / 6
PQR          1 / 0       0 / 1       3 / 6 / 6

#create new columns names
c = df.columns.to_series().str.split(" / ", expand=True).stack().values.tolist()
print (c)
["North", "South", "East", "West", "No1", "No2", "No3"]

#list comprehension with split to df and concat output
df = pd.concat([df[x].str.split(" / ", expand=True) for x in df], axis=1)
print (df)
0  1  0  1   0  1  2
Name
ABC   0  1  0  0  10  3  6
XYZ   1  0  0  1   4  5  6
PQR   1  0  0  1   3  6  6

#assign new columns names
df.columns = c
df = df.reset_index()
print (df)
Name North South East West No1 No2 No3
0  ABC     0     1    0    0  10   3   6
1  XYZ     1     0    0    1   4   5   6
2  PQR     1     0    0    1   3   6   6

Складання часу:

df = pd.concat([df]*1000).reset_index(drop=True)
print (df)

def f(df):
return pd.concat([s.str.split(" / ").apply(pd.Series, index=c.split(" / ")) for c, s in df.set_index("Name").iteritems()], axis=1).reset_index()
print (f(df))

def f1(df):
cols = df.columns[~df.columns.str.contains("/")].tolist()
df = df.set_index(cols)
c = df.columns.to_series().str.split(" / ", expand=True).stack().values.tolist()
df = pd.concat([df[x].str.split(" / ", expand=True) for x in df], axis=1)
df.columns = c
return df.reset_index()
print (f1(df))

In [142]: %timeit (f(df))
1 loop, best of 3: 2.6 s per loop

In [143]: %timeit (f1(df))
10 loops, best of 3: 27.5 ms per loop

1 для відповіді № 2

Ось один підхід

In [1417]: pd.concat([s.str.split(" / ").apply(pd.Series, index=c.split(" / "))
for c, s in df.set_index("Name").iteritems()],
axis=1).reset_index()
Out[1417]:
Name North South East West No1 No2 No3
0  ABC     0     1    0    0  10   3   6
1  XYZ     1     0    0    1   4   5   6
2  PQR     1     0    0    1   3   6   6