代码之家  ›  专栏  ›  技术社区  ›  Stanko

基于现有列向数据框架添加多行和单列

  •  2
  • Stanko  · 技术社区  · 6 年前

    我要添加新行,并基于现有列添加新列。例如,假设我有以下数据帧:

       A          B
       1          a
       2          b
       3          c
       4          b
    

    以及一个以唯一的B列值作为键的字典。每个键都与一个值列表相关联。这些值用于新的行和列: {a: [x, y, z], b: [x, w, r], c: [x, q]}

    转换应导致以下数据帧:

       A          C          
       1          x
       1          y
       1          z
       2          x
       2          w
       2          r
       3          x
       3          q
       4          x
       4          w
       4          r
    

    我知道如何添加一个新列,但是我一直在尝试复制行。解决这个问题最有效的方法是什么?我是更新现有的数据帧还是创建新的数据帧?

    更新

    该操作将在使用DASK的大型数据帧(20 milion+行)上使用。

    4 回复  |  直到 6 年前
        1
  •  2
  •   jezrael    6 年前

    我建议创建新的 map , np.repeat chain.from_iterable :

    d = {'a': ['x', 'y', 'z'], 'b': ['x', 'w', 'r'], 'c': ['x', 'q']}
    
    s = df['B'].map(d)
    lens = [len(x) for x in s]
    
    from itertools import chain
    
    df = pd.DataFrame({
        'A' : df['A'].values.repeat(lens),
        'C' : list(chain.from_iterable(s.values.tolist()))
    })
    print (df)
        A  C
    0   1  x
    1   1  y
    2   1  z
    3   2  x
    4   2  w
    5   2  r
    6   3  x
    7   3  q
    8   4  x
    9   4  w
    10  4  r
    

    如果字典的某个值不匹配,则使用更通用的解决方案:

    第一个解决方案返回错误,因为 地图 返回缺少的值:

    类型错误:“nonetype”类型的对象没有len()。

    print (df)
       A  B
    0  1  d <- change data
    1  2  b
    2  3  c
    3  4  b
    
    d = {'a': ['x', 'y', 'z'], 'b': ['x', 'w', 'r'], 'c': ['x', 'q']}
    
    s = [d.get(x, [x]) for x in df['B']]
    print (s)
    [['d'], ['x', 'w', 'r'], ['x', 'q'], ['x', 'w', 'r']]
    
    lens = [len(x) for x in s]
    
    from itertools import chain
    
    df = pd.DataFrame({
        'A' : df['A'].values.repeat(lens),
        'B' : list(chain.from_iterable(s))
    })
    print (df)
       A  B
    0  1  d
    1  2  x
    2  2  w
    3  2  r
    4  3  x
    5  3  q
    6  4  x
    7  4  w
    8  4  r
    

    因为使用 dask ,另一个解决方案应该是:

    d = {'a': ['x', 'y', 'z'], 'b': ['x', 'w', 'r'], 'c': ['x', 'q']}
    df1 = pd.DataFrame([(k, y) for k, v in d.items() for y in v], columns=['B','C'])
    print (df1)
       B  C
    0  a  x
    1  a  y
    2  a  z
    3  b  x
    4  b  w
    5  b  r
    6  c  x
    7  c  q
    
    df = df.merge(df1, on='B', how='left')
    print (df)
        A  B  C
    0   1  a  x
    1   1  a  y
    2   1  a  z
    3   2  b  x
    4   2  b  w
    5   2  b  r
    6   3  c  x
    7   3  c  q
    8   4  b  x
    9   4  b  w
    10  4  b  r
    
        2
  •  2
  •   JoergVanAken    6 年前

    您可以将dict转换为数据框,其中列名为 B C

    df2 = pd.DataFrame.from_dict(d, orient='index').stack().reset_index().iloc[:, [0, -1]]
    df2.columns = ['B', 'C']
    

    合并这个新的 df2 用你的首字母 df 并选择您想要的数据:

    df.merge(df2, on='B').set_index('A')['C'].sort_index()
    
        3
  •  2
  •   anky    6 年前

    另一种方法使用 sum() map() :

    d = {'a': ['x', 'y', 'z'], 'b': ['x', 'w', 'r'], 'c': ['x', 'q']}
    df_new= pd.DataFrame({'A': np.repeat(df.A,df.B.map(d).apply(len)).\
                  reset_index(drop=True),'B':df.B.map(d).sum()})
    

    或者更好地使用operator reduce(对于大型数据帧) :

    import functools,operator
    df_new= pd.DataFrame({'A': np.repeat(df.A,df.B.map(d).apply(len)).\
                      reset_index(drop=True),'B':functools.reduce(operator.iadd, df.B.map(d),[])})
    print(df_new)
    
        A  B
    0   1  x
    1   1  y
    2   1  z
    3   2  x
    4   2  w
    5   2  r
    6   3  x
    7   3  q
    8   4  x
    9   4  w
    10  4  r
    
        4
  •  1
  •   Josh Friedlander    6 年前

    我的答案是-制造一个新的测向仪。

    di = {'a': ['x', 'y', 'z'], 'b': ['x', 'w', 'r'], 'c': ['x', 'q']}
    x = df.to_dict()
    temp = list(zip(df.A, [di[z] for z in x['B'].values()]))
    A = [[x[0]] * len(x[1]) for x in temp]
    B = [x[1] for x in temp]
    
    A = [item for sublist in A for item in sublist]
    B = [item for sublist in B for item in sublist]
    
    pd.DataFrame({'A':A, 'B':B})