【问题标题】:How to append columns based on other column values to pandas dataframe如何将基于其他列值的列附加到熊猫数据框
【发布时间】:2016-01-27 03:54:21
【问题描述】:

我有以下问题:我想将列附加到数据框。这些列是该数据框另一行中的唯一值,填充了该值在该行中的出现。它看起来像这样:

df:

   Column1  Column2
0     1       a,b,c
1     2       a,e
2     3       a
3     4       c,f
4     5       c,f

我想要得到的是:

    Column1  Column2  a  b  c  e  f
0     1       a,b,c   1  1  1
1     2       a,e     1        1
2     3       a       1
3     4       c,f           1     1
4     5       c,f           1     1

(空格可以是nan也可以是0,没关系)

我现在已经编写了一些代码来实现这一点,但是它不是附加列,而是附加行,所以我的输出看起来像这样:

        Column1  Column2
    0     1       a,b,c
    1     2       a,e
    2     3       a
    3     4       c,f
    4     5       c,f
    a     1        1
    b     1        1
    c     1        1
    e     1        1
    f     1        1

代码如下所示:

def NewCols(x):
    for i, value in df['Column2'].iteritems():
        listi=value.split(',')
        for value in listi:
            string = value
            x[string]=list.count(string)
    return x

df1=df.apply(NewCols)

我在这里尝试做的是遍历数据帧的每一行,并以逗号分割 Column2 中包含的字符串 (a,b,c),因此变量 listi 然后是一个包含分隔字符串值的列表。然后,对于每个值,我想创建一个新列并用listi 中该值的出现次数填充它。我很困惑为什么代码会附加行而不是列。有人知道为什么以及如何纠正吗?

【问题讨论】:

    标签: python pandas append dataframe


    【解决方案1】:

    当您使用apply 时,它会为每一列调用一次您的函数,并将该列作为参数。因此,您的 NewCols 中的 x 将设置为单列。当您执行x[string] = list.count(string) 时,您正在向该列添加值。由于 每个 列都调用了apply,因此您最终以这种方式将值附加到两列。

    apply 在您的计算仅取决于单个列的值时不是正确的选择。相反,请使用map。在这种情况下,您需要编写一个 NewCol 函数,该函数接受单个 Column2 值并返回单行的数据。您可以将其作为字典返回,或者方便地返回类似字典的对象,例如 collections.Counter。然后,您需要将此新行数据包装到 DataFrame 中,并使用 concat 将其按列附加到现有数据。这是一个例子:

    def NewCols(val):
        return collections.Counter(val.split(','))
    
    >>> pandas.concat([d, pandas.DataFrame.from_records(d.Column2.map(NewCols))], axis=1)
       Column1 Column2   a   b   c   e   f
    0        1   a,b,c   1   1   1 NaN NaN
    1        2     a,e   1 NaN NaN   1 NaN
    2        3       a   1 NaN NaN NaN NaN
    3        4     c,f NaN NaN   1 NaN   1
    4        5     c,f NaN NaN   1 NaN   1
    

    对于这个特定的计算,你实际上根本不需要编写自己的函数,因为pandas 在.str 方法访问器下内置了split 作为操作。所以你可以这样做:

    >>> pandas.concat([d, pandas.DataFrame.from_records(d.Column2.str.split(',').map(collections.Counter))], axis=1)
       Column1 Column2   a   b   c   e   f
    0        1   a,b,c   1   1   1 NaN NaN
    1        2     a,e   1 NaN NaN   1 NaN
    2        3       a   1 NaN NaN NaN NaN
    3        4     c,f NaN NaN   1 NaN   1
    4        5     c,f NaN NaN   1 NaN   1
    

    【讨论】:

    • 感谢详细的回复!但是代码给我带来了一个关键错误...KeyError: 0L知道原因可能是什么吗?
    • @sequence_hard:不确定,我无法重现该错误。
    【解决方案2】:

    虽然我们可以使用get_dummies 做到这一点,但我们也可以作弊并直接使用pd.value_counts

    >>> df = pd.DataFrame({'Column1': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5}, 'Column2': {0: 'a,b,c', 1: 'a,e', 2: 'a', 3: 'c,f', 4: 'c,f'}})
    >>> df.join(df.Column2.str.split(",").apply(pd.value_counts).fillna(0))
       Column1 Column2  a  b  c  e  f
    0        1   a,b,c  1  1  1  0  0
    1        2     a,e  1  0  0  1  0
    2        3       a  1  0  0  0  0
    3        4     c,f  0  0  1  0  1
    4        5     c,f  0  0  1  0  1
    

    一步一步,我们有

    >>> df.Column2.str.split(",")
    0    [a, b, c]
    1       [a, e]
    2          [a]
    3       [c, f]
    4       [c, f]
    dtype: object
    >>> df.Column2.str.split(",").apply(pd.value_counts)
        a   b   c   e   f
    0   1   1   1 NaN NaN
    1   1 NaN NaN   1 NaN
    2   1 NaN NaN NaN NaN
    3 NaN NaN   1 NaN   1
    4 NaN NaN   1 NaN   1
    >>> df.Column2.str.split(",").apply(pd.value_counts).fillna(0)
       a  b  c  e  f
    0  1  1  1  0  0
    1  1  0  0  1  0
    2  1  0  0  0  0
    3  0  0  1  0  1
    4  0  0  1  0  1
    >>> df.join(df.Column2.str.split(",").apply(pd.value_counts).fillna(0))
       Column1 Column2  a  b  c  e  f
    0        1   a,b,c  1  1  1  0  0
    1        2     a,e  1  0  0  1  0
    2        3       a  1  0  0  0  0
    3        4     c,f  0  0  1  0  1
    4        5     c,f  0  0  1  0  1
    

    【讨论】:

    • 工作完美,谢谢你的详细解释,我明白了:-)。
    • 为什么使用value_counts 而不是get_dummies 被认为是作弊? :)
    【解决方案3】:

    你可以这样使用:

    import pandas as pd
    import sklearn.feature_extraction.text
    
    vect = sklearn.feature_extraction.text.CountVectorizer(binary=True,   token_pattern=u'(?u)\\b\\w+\\b')
    df = ...
    v = [a for a in df['Column2']]
    new_df = df.combine_first( pd.DataFrame(vect.fit_transform(v).todense(), columns=vect.get_feature_names()) )
    print new_df
    

    干杯!

    【讨论】:

    • 您可以通过注释代码来改进您的答案!
    猜你喜欢
    • 2014-01-03
    • 1970-01-01
    • 2018-06-28
    • 2017-03-03
    • 2023-03-17
    • 1970-01-01
    • 2020-10-21
    • 2017-06-13
    • 2020-05-31
    相关资源
    最近更新 更多