Python 熊猫:将数据帧列(一个系列)中的分隔值拆分为多列。优雅的解决方案?
我在DataFrame中有一列(csv中的一列)是逗号分隔的值。我想将此列拆分为多个列 这是一个老问题,这里也讨论过,但有一个特点:一个条目可能来自Python 熊猫:将数据帧列(一个系列)中的分隔值拆分为多列。优雅的解决方案?,python,pandas,mapping,dataframe,series,Python,Pandas,Mapping,Dataframe,Series,我在DataFrame中有一列(csv中的一列)是逗号分隔的值。我想将此列拆分为多个列 这是一个老问题,这里也讨论过,但有一个特点:一个条目可能来自0-n逗号分隔的值。例如: df.head(): i: vals | sth_else --------------------- 1: a,b,c | ba 2: a,d | be 3: | bi 4: e,a,c | bo 5: e | bu 我希望得到以下输出(或类似输出,如真/假): 我目前正在试验
0-n
逗号分隔的值。例如:
df.head():
i: vals | sth_else
---------------------
1: a,b,c | ba
2: a,d | be
3: | bi
4: e,a,c | bo
5: e | bu
我希望得到以下输出(或类似输出,如真/假):
我目前正在试验Series.str.split
和Series.to_dict
函数,但没有任何令人满意的结果(总是导致ValueError:数组的长度必须相同
)
此外,我总是试图找到优雅的解决方案,这些解决方案在几个月后看起来很容易理解;)。在任何情况下,我们都非常感谢您的建议
下面是用于测试的dummy.csv
vals;sth_else
a,b,c;ba
a,d;be
;bi
e,a,c;bo
e;bu
这与今天的另一个问题非常相似。正如我在那个问题中所说的,可能有一种简单的方法可以做到这一点,但我也发现简单地创建一个新的数据框并通过以下方式迭代原始数据框来填充它是很方便的:
#import and create your data
import pandas as pd
DF = pd.DataFrame({ 'vals' : ['a,b,c', 'a,d', '', 'e,a,c', 'e'],
'other' : ['ba', 'be', 'bi', 'bo', 'bu']
}, dtype = str)
现在创建一个新的数据框,其中DF
中的other
列作为索引,列是从DF
中的val
列中找到的唯一字符中提取的:
New_DF = pd.DataFrame({col : 0 for col in
set([letter for letter in ''.join([char for char in DF.vals.values])
if letter.isalpha()])},
index = DF.other)
In [51]: New_DF
Out[51]:
a b c d e
other
ba 0 0 0 0 0
be 0 0 0 0 0
bi 0 0 0 0 0
bo 0 0 0 0 0
bu 0 0 0 0 0
现在,只需在新的_DF
索引上迭代,将原始的DF
按该值切片,然后在列上迭代,查看它们是否出现在相关的_字符串中
:
for ind in New_DF.index:
relevant_string = str(DF[DF.other == ind].vals.values)
for col in list(New_DF.columns):
if col in relevant_string:
New_DF.loc[ind, col] += 1
输出如下所示
In [54]: New_DF
Out[54]:
a b c d e
other
ba 1 1 1 0 0
be 1 0 0 1 0
bi 0 0 0 0 0
bo 1 0 1 0 1
bu 0 0 0 0 1
太快了!而且看起来很不错,谢谢!只需要一点补充说明:您将熊猫作为np导入—我想应该是pd;)没什么难堪的,只是有点困惑。我必须说这是一个非常酷的解决方案。但也许有几条评论可以解释这两行的意思。我还在破译=)@dmeu刚刚添加了一些评论,希望现在更清楚了。:-)嘿,还有-非常快!谢谢你的提议,顺便说一句,Woody Pride,这是另一个类似的问题,我可以看一看。对于那些偶然发现以下答案的人,我认为这里的答案绝对是最好的:@Alexpetaria确实如此!这才是真正的熊猫方式——你为什么不把它也添加到这里的答案中呢?
In [54]: New_DF
Out[54]:
a b c d e
other
ba 1 1 1 0 0
be 1 0 0 1 0
bi 0 0 0 0 0
bo 1 0 1 0 1
bu 0 0 0 0 1
import pandas as pd
from StringIO import StringIO # py2.7 used here
# from io.StringIO import StringIO if you have py3.x
# data
# ==================================================================
csv_buffer = 'vals;sth_else\na,b,c;ba\na,d;be\n;bi\ne,a,c;bo\ne;bu'
df = pd.read_csv(StringIO(csv_buffer), sep=';')
Out[58]:
vals sth_else
0 a,b,c ba
1 a,d be
2 NaN bi
3 e,a,c bo
4 e bu
# processing
# ==================================================================
def func(group):
return pd.Series(group.vals.str.split(',').values[0], name='vals')
ser = df.groupby(level=0).apply(func)
Out[60]:
0 0 a
1 b
2 c
1 0 a
1 d
2 0 NaN
3 0 e
1 a
2 c
4 0 e
Name: vals, dtype: object
# use get_dummies, and then aggregate for each column of a b c d e to be its max (max is always 1 in this case)
pd.get_dummies(ser)
Out[85]:
a b c d e
0 0 1 0 0 0 0
1 0 1 0 0 0
2 0 0 1 0 0
1 0 1 0 0 0 0
1 0 0 0 1 0
2 0 0 0 0 0 0
3 0 0 0 0 0 1
1 1 0 0 0 0
2 0 0 1 0 0
4 0 0 0 0 0 1
# do this groupby on outer index level [0,1,2,3,4] and reduce any inner group from multiple rows to one row
df_dummies = pd.get_dummies(ser).groupby(level=0).apply(lambda group: group.max())
Out[64]:
a b c d e
0 1 1 1 0 0
1 1 0 0 1 0
2 0 0 0 0 0
3 1 0 1 0 1
4 0 0 0 0 1
df_dummies['sth_else'] = df.sth_else
Out[67]:
a b c d e sth_else
0 1 1 1 0 0 ba
1 1 0 0 1 0 be
2 0 0 0 0 0 bi
3 1 0 1 0 1 bo
4 0 0 0 0 1 bu