Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 创建数据帧中是否存在字符串的二进制表示形式_Python_Python 3.x_Pandas - Fatal编程技术网

Python 创建数据帧中是否存在字符串的二进制表示形式

Python 创建数据帧中是否存在字符串的二进制表示形式,python,python-3.x,pandas,Python,Python 3.x,Pandas,我有一个Pandas数据框,它由几列组成,其中的单元格可能包含字符串,也可能不包含字符串。例如: import numpy as np import pandas as pd df = pd.DataFrame({'A':['asfe','eseg','eesg','4dsf','','hdt','gase','gex','gsges','hhbr'], 'B':['','bdb','htsdg','','rdshg','th','tjf','','','

我有一个Pandas数据框,它由几列组成,其中的单元格可能包含字符串,也可能不包含字符串。例如:

import numpy as np
import pandas as pd

df = pd.DataFrame({'A':['asfe','eseg','eesg','4dsf','','hdt','gase','gex','gsges','hhbr'],
                   'B':['','bdb','htsdg','','rdshg','th','tjf','','',''],
                   'C':['hrd','jyf','sef','hdsr','','','','','hdts','aseg'],
                   'D':['','','hdts','afse','nfd','','htf','','',''],
                   'E':['','','','','jftd','','','','jfdt','']})
…看起来像:

       A      B     C     D     E
0   asfe          hrd            
1   eseg    bdb   jyf            
2   eesg  htsdg   sef  hdts      
3   4dsf         hdsr  afse      
4         rdshg         nfd  jftd
5    hdt     th                  
6   gase    tjf         htf      
7    gex                         
8  gsges         hdts        jfdt
9   hhbr         aseg            
我想创建一个列,该列包含一个二进制表示形式,表示该列是否包含字符串;例如,第一行将表示为10100

我能想到的唯一方法是:

  • 创建一个临时数据框
  • 逐列检查单元格是否包含任何内容 字符,并表示为0/1
  • 将二进制结果连接到单个字符串中
  • 将列从头开始复制到原始数据帧
  • 这是我创建的代码:

    scratchdf = pd.DataFrame().reindex_like(df)
    
    for col in df.columns.values:
        scratchdf[col] = df[col].str.contains(r'\w+',regex = True).astype(int)
    
    scratchdf['bin'] =  scratchdf['A'].astype(str) + \
                        scratchdf['B'].astype(str) + \
                        scratchdf['C'].astype(str) + \
                        scratchdf['D'].astype(str) + \
                        scratchdf['E'].astype(str)
    
    df = df.join(scratchdf['bin'])
    
    …生成最终数据帧:

           A      B     C     D     E    bin
    0   asfe          hrd              10100
    1   eseg    bdb   jyf              11100
    2   eesg  htsdg   sef  hdts        11110
    3   4dsf         hdsr  afse        10110
    4         rdshg         nfd  jftd  01011
    5    hdt     th                    11000
    6   gase    tjf         htf        11010
    7    gex                           10000
    8  gsges         hdts        jfdt  10101
    9   hhbr         aseg              10100
    

    这是可行的,但似乎有点浪费(特别是对于大型数据帧)。有没有一种方法可以直接创建二进制表示列,而无需创建临时数据帧?

    首先检查空字符串或转换为
    bool
    ,然后转换为
    int
    str
    和最后一个
    连接
    sum

    df['new'] = (df != '').astype(int).astype(str).apply(''.join, axis=1)
    
    #faster alternative
    df['new'] = (df != '').astype(int).astype(str).values.sum(axis=1)
    
    print (df)
    
           A      B     C     D     E    new
    0   asfe          hrd              10100
    1   eseg    bdb   jyf              11100
    2   eesg  htsdg   sef  hdts        11110
    3   4dsf         hdsr  afse        10110
    4         rdshg         nfd  jftd  01011
    5    hdt     th                    11000
    6   gase    tjf         htf        11010
    7    gex                           10000
    8  gsges         hdts        jfdt  10101
    9   hhbr         aseg              10100
    
    计时

    df = pd.concat([df] * 1000, ignore_index=True)
    
    In [99]: %timeit df.astype(bool).astype(int).astype(str).values.sum(axis=1)
    10 loops, best of 3: 155 ms per loop
    
    In [100]: %timeit (df != '').astype(int).astype(str).values.sum(axis=1)
    10 loops, best of 3: 158 ms per loop
    
    In [101]: %timeit (df != '').astype(int).astype(str).apply(''.join, axis=1)
    1 loop, best of 3: 330 ms per loop
    
    In [102]: %timeit df.astype(bool).astype(int).astype(str).apply(''.join, axis=1)
    1 loop, best of 3: 326 ms per loop
    
    In [103]: %timeit df.astype(bool).astype(int).apply(lambda row: ''.join(str(i) for i in row), axis=1)
    1 loop, best of 3: 210 ms per loop
    

    您可以使用以下事实:空字符串对应于False,非空字符串对应于True。因此,将字符串dataframe强制转换为bool会将dataframe设置为true和false。将此值重新转换为int将true转换为1,将false转换为0,然后只需跨行应用联接操作:

    df['binary'] = df.astype(bool).astype(int).apply(
        lambda row: ''.join(str(i) for i in row), axis=1)
    print(df)
    
    结果:

           A      B     C     D     E  binary
    0   asfe          hrd              10100
    1   eseg    bdb   jyf              11100
    2   eesg  htsdg   sef  hdts        11110
    3   4dsf         hdsr  afse        10110
    4         rdshg         nfd  jftd  01011
    5    hdt     th                    11000
    6   gase    tjf         htf        11010
    7    gex                           10000
    8  gsges         hdts        jfdt  10101
    9   hhbr         aseg              10100
    
    编辑:刚刚意识到另一个用户发布了基本相同的东西(也修复了复制错误)

    下面是使用生成器的另一种方法:

    def iterable_to_binary_mask(iterable):
        bools = (bool(i) for i in iterable)
        ints = (int(i) for i in bools)
        strs = (str(i) for i in ints)
        return ''.join(strs)
    
    df['binary'] = df.apply(iterable_to_binary_mask, axis=1)
    
    这大约比我机器上的类型转换方法慢3倍,但应该使用
    最小内存

    方法1

    a = np.where(df != "", "1", "0").astype("|S1")
    df["bin"] = np.apply_along_axis(lambda x: x.tostring().decode("utf-8"), 1, a)
    
    方法2

    df["bin"] = np.append(
                   np.where(df != "", "1", "0").astype("S1"), 
                   np.array([["\n"]]).astype("S1").repeat(df.shape[0], axis=0), 
                   axis=1
                ).tostring().decode("utf-8")[:-1].split("\n")
    
    方法2将
    \n
    追加到numpy数组的末尾

    array([[b'1', b'0', b'1', b'0', b'0', b'\n'],
           [b'1', b'1', b'1', b'0', b'0', b'\n'],
           [b'1', b'1', b'1', b'1', b'0', b'\n'],
           ...,
           [b'1', b'0', b'0', b'0', b'0', b'\n'],
           [b'1', b'0', b'1', b'0', b'1', b'\n'],
           [b'1', b'0', b'1', b'0', b'0', b'\n']], dtype='|S1')
    
    然后调用
    tostring
    decode
    。删除最后一个“\n”,然后用“\n”拆分

    方法3(使用
    视图
    参考:)

    时间: 耶斯雷尔的重复实验

    In [99]: %timeit df.astype(bool).astype(int).astype(str).values.sum(axis=1)
    28.9 ms ± 782 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
    In [100]: %timeit (df != '').astype(int).astype(str).values.sum(axis=1)
    29 ms ± 645 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
    In [101]: %timeit (df != '').astype(int).astype(str).apply(''.join, axis=1)
    168 ms ± 2.93 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    In [102]: %timeit df.astype(bool).astype(int).astype(str).apply(''.join, axis=1)
    173 ms ± 7.36 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    In [103]: %timeit df.astype(bool).astype(int).apply(lambda row: ''.join(str(i) for i in row), axis=1)
    159 ms ± 3.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    

    非常感谢你的回答。非常有用,特别是建议方法的不同时间。非常感谢您的解决方案。您和@jezreal的回答都非常有用。我选择了jezreal的答案作为接受答案,因为时间安排显示了不同的组件如何进行比较,但我对你的答案投了赞成票,并且它为问题提供了一个有效的答案。刚刚注意到我的打字错误:@jezrael。对不起,我编辑了我的答案并获得了更多的加速。如果你需要的话,让你知道。谢谢你为回答这个问题所做的所有工作。我总是忘了看numpy中可用的选项,但这个答案表明它可以带来一些非常实时和高效的好处。非常酷。@user1718097没问题。有趣的问题:PBut刚刚注意到输出是01011而不是10100;我认为.where()方法应该是np.where(df!=“1”、“0”)而不是:-)
    (Based on jezrael's setup df = pd.concat([df] * 1000, ignore_index=True))
    
    # method 2
    %timeit np.append(np.where(df != "", "1", "0").astype("S1"), np.array([["\n"]]).astype("S1").repeat(df.shape[0], axis=0), axis=1).tostring().decode("utf-8")[:-1].split("\n")
    12.3 ms ± 175 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    # method 3
    %timeit np.ascontiguousarray(np.where(df != "", "1", "0").astype("S1")).view('|S5').astype(str)
    12.8 ms ± 164 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    # method 1 (slower)
    %timeit np.apply_along_axis(lambda x: x.tostring().decode("utf-8"), 1, np.where(df != "", "1", "0").astype("S1"))
    45 ms ± 1.86 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    
    In [99]: %timeit df.astype(bool).astype(int).astype(str).values.sum(axis=1)
    28.9 ms ± 782 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
    In [100]: %timeit (df != '').astype(int).astype(str).values.sum(axis=1)
    29 ms ± 645 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
    In [101]: %timeit (df != '').astype(int).astype(str).apply(''.join, axis=1)
    168 ms ± 2.93 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    In [102]: %timeit df.astype(bool).astype(int).astype(str).apply(''.join, axis=1)
    173 ms ± 7.36 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    In [103]: %timeit df.astype(bool).astype(int).apply(lambda row: ''.join(str(i) for i in row), axis=1)
    159 ms ± 3.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)