【问题标题】:pandas: Split separated values in a DataFrame column (one Series) into multiple Columns. Elegant solutions?pandas:将 DataFrame 列(一个系列)中的分隔值拆分为多个列。优雅的解决方案?
【发布时间】:2015-09-28 19:48:20
【问题描述】:

我在 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

我想要以下输出(或类似的输出,例如 True/False):

i : a | b | c | d | e |  sth_else 
-----------------------------------
1:  1 | 1 | 1 | 0 | 0 | ba
2:  1 | 0 | 0 | 1 | 0 | be
3:  0 | 0 | 0 | 0 | 0 | bi
4:  1 | 0 | 1 | 0 | 1 | bo
5:  0 | 0 | 0 | 0 | 1 | bu

我目前正在试验Series.str.split,然后是Series.to_dict 函数,但没有任何令人满意的结果(导致总是ValueError: arrays must all be same length。:)

另外,我总是试图找到优雅的解决方案,几个月后查看这些解决方案很容易理解;)。无论如何,建议非常感谢!

这是用于测试的dummy.csv

vals;sth_else 
a,b,c;ba
a,d;be
;bi
e,a,c;bo
e;bu

【问题讨论】:

  • 对于那些偶然发现以下答案的人,我认为这里的答案绝对优越:stackoverflow.com/questions/28121682/…
  • @AlexPetralia 确实如此!那是真正的熊猫方式 - 你为什么不把它也添加到这里的答案中?

标签: python pandas mapping dataframe series


【解决方案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

【讨论】:

  • 那是!而且看起来很不错,谢谢!只是一点点说明:您将 pandas 导入为 np - 我想应该是 pd ;)
  • 没什么尴尬的,只是有点困惑。我必须说这是一个非常酷的解决方案。但也许有几个 cmets 可以解释两行二会很棒。我还在破译=)
  • @dmeu 刚刚添加了一些 cmets,希望现在更清楚。 :-)
【解决方案2】:

这与今天的另一个问题非常相似。正如我在那个问题中所说,可能有一种简单优雅的 pandas 方法可以做到这一点,但我也发现简单地创建一个新数据框并通过以下方式迭代原始数据框来填充它很方便:

#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

现在只需遍历New_DF 的索引,将原始DF 切片为该值并遍历列以查看它们是否出现在relevant_string 中:

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

【讨论】:

猜你喜欢
  • 2016-11-17
  • 1970-01-01
  • 2016-09-10
  • 1970-01-01
  • 2021-03-05
  • 1970-01-01
  • 2018-07-27
  • 1970-01-01
相关资源
最近更新 更多