平常遇到的一些问题及问题的解决办法

这些问题的记录将以问题出现的时间为轴。格式为问题、细节、时间、解决方法、原因。

问题:pandas查询那些列含有空值

df.isnull().any()

问题:pandas查询那些列全部为空值

df.isnull().all()

问题:pandas0.24.2里根据列值拼接表报错“ValueError: You are trying to merge on object and int64 columns. If you wish to proceed you should use pd.concat”

只部分解决,换join为merge。尝试在读时候设定数值索引类型时没成功,之后尝试改变数值索引也没成功。

问题:数据库更新方式:全量更新、增量更新

就是这个意思,更新方式对数据表的数据无影响,是否覆盖旧数据才有影响。 采用全量更新不覆盖旧数据的更新方式得到的数据表,任意时间点(即任意dt)的数据均是此表此时间点的全量数据; 采用增量更新不覆盖旧数据的更新方式得到的数据表,任意时间点(即任意dt)的数据加上往期数据才是此表此时间点的全量数据。 所以为取得全量数据,全量更新可仅取最大dt,增量更新需取所有dt。

问题:pandas的dataframe里某列为字符串,但字符串内部为字典、列表或嵌套列表,根据逻辑拆分此列。

这种字符串内部是字典等的列需拆分,用正则表达式显然不是最简单的方法。首先,列内是字符,希望变成字典等,可对此列记为'a'转换为字典df['a'].apply(eval),如需要拆分出'va'等值并命名为列'ka',可df['ka'] = df['a'].apply(eval).apply(lambda x: x['ka'])。当然列'a'可能并不是全部为字典,还可能含有空值,空值无法eval,这个时候可专门索引非空者。具体代码为:

# 列a非空的索引
column_a_not_null_index = df[df['a'].notnull()].index 
df.loc[column_a_not_null_index, 'a'] = \
df.loc[column_a_not_null_index, 'a'].apply(eval)
df['ka'] = np.nan 
#为保证字典含有特定键、列表含有特定位置的索引,可能在此位置还需更细致的索引
df.loc[column_a_not_null_index, 'ka'] = \
df.loc[column_a_not_null_index, 'a'].apply(lambda x: x['ka'])

问题:pyspark读取Hive表格,为运行效率想只读取几个字段,但是不知道字段名字,如何得到字段名字

部分解决,即限制读取量的方法达到运行效率,代码为:

spark.sql("select * from tablename limit 5").show()

应该是有更直接方式,但暂未找到。

问题:python pandas:将一个带参数的函数应用于一个Series

慕田峪9158850在猿问中的回答,可:

应该是有更直接方式,但暂未找到。

问题:pyspark内hive数据库的数据,如何获得字段名。

但其实有更好更直接的方法。 * 时间:20190911 * 解决办法:

columns = spark.sql("select * from tablename").columns

按同事说法,这样不会真的读取全表,没很大开销,我运行之后也感觉是这样。

可能还会想获得hive表格的元数据(即字段名、字段类型等),可采用:

spark.sql("desc formatted tablename").collect()

问题:虚拟机软件无法创建64位虚拟机?

根据virtualbox论坛-I have a 64bit host, but can't install 64bit guestsvirtualbox论坛-[Solved] VT-x is not available, no solutions have worked说法, virtualbox及其他虚拟机软件创建64位系统,需满足: * cpu为64位并硬件上支持虚拟化(Intel VT-x or AMD-v),这只能根据型号查询。 * 开启了虚拟化,可在BIOS上开启,并可通过Intel或AMD软件、任务管理器查询。 * 现在硬件和出厂应该均能支持前两者,那么要保证其他软件、进程等不占用虚拟化。 mpack列举了一些占用虚拟化的程序和进程等,只能对应去试错了。 我根据提示关闭了windows安全中心-设备安全性-内核隔离-内存完整性,即可创建54位虚拟机。

问题:表内某列为列表(字典,甚至字典与列表的层层嵌套),如何根据这列将表格拆分成不含列表、字典的新表,而表的条目根据其内元素值相应增加?

读取发现,甚至里面还不是列表、字典,而是列表、字典的字符串形式。可先对此列采用apply(eval)(注:若此列还含有空值,要仅对非空值部分采用此函数)。然后可对此列采用df['a'].apply(pd.Series)pd.DataFrame(df['a'].tolist(), index=df.index),其中后者效率明显高于前者(30分钟、2分钟)。若是字典,会自动将键作为列名;而列表,其列名是从0开始的数字,没有意义可删除;列表,很多时候不等长,这样产生的新表df1的列数将是列表最大长度,其中必然含有很多空值。没关系,再运用.stack(),将达到问题要求,且不会引入这些空值。多层嵌套的情况只需将上述步骤重复相应遍数。

拆分后,为进一步拆分,也为相应增加行,我们可能.stack()以达到表仅含一个列,同时其他列的信息也没丢弃,其他列的信息将在多层索引里面。注意.stack()后是Series对象,但因为含有列表等,拆分后将引入无意义列名0-n,.stack()将变成无意义索引,需删除,删除后需重新设置多层索引,此时很可能是单列多重索引的DataFrame对象,需取出对应的Series对象。因为拆分列表/字典列时候是对Series对象进行拆分,而不是DataFrame对象,即使DataFrame对象仅含一列。还需要注意,若索引达到或超过5层将报错,切出相应列之后再拼接吧。 例如df含有a、b、c三列,c列为列表嵌套字典组成的字符串(还含有空值),c列的第一层为不等长列表,c列的第二层为含有键key1、key2、key3的字典,需要从c中拆分出有用字段。

# 将列a、b信息保存在多重索引里
df = df.set_index(['a', 'b'])
# 仅对非空部分处理,否则报错
df1 = df[df['c'].notnull()]
df2 = df[df['c'].isnull()]
# 字符串形式不方便拆分,转换成列表嵌套字典
df2['c'] = df2['c'].apply(eval)
# 拆分成多列,由于列长不等,会引入空值
df3 = pd.DataFrame(df1['c'].tolist(), index=df1.index)
# 没关系,堆叠后没有这些空值
ser1 = df3.stack()
# 差分列表列将引入索引位置作为列名,这没意义,删除并重新使得数据仅含一列,其他均为索引
# 选取DataFrame仅有列形成Series,
# 由于没指定列名,其将自动生成列名数字0
ser2 = ser1.reset_index().drop(['level_1'], axis=1).set_index(['a', 'b'])[0]
# 再次拆分内层字典
df4 = pd.DataFrame(ser2.tolist(), index=df1.index)
# 与原来的空值数据合并
df5 = pd.concat([df4, df1], axis=0)
# 至此打得到目标

问题:根据df_a的column_a和df_b的column_b连接这两个表,其中column_a中每个位置均是列表/字典/集合等,而column_b则每个位置仅含单个元素,若column_b属于column_a则连接成功,该怎么做呢?

暂无更好办法,我的方法是依据上个问题方法差分列之后join或merge,但是注意保存列表列,这样省得再找办法合并列。

问题:如何将多列合并成一列,键为列名,值为相应列值。

暂无更好办法,我的方法是依据上个问题方法差分列之后join或merge,但是注意保存列表列,这样省得再找办法合并列。

问题:如何根据某一列,形成关于此列的画像?

问题:条件查询中查询字段中含有空字符

如是在pyspark中:

spark.sql("select * from b where b='12345   '")

问题:数据有列a和列b,a为状态,b为日期,想知道状态持续时间。

暂时思路,pyspark里可以设置window函数,如下:

w =  Window.partitionBy(df.k).orderBy(df.v)

其中.partitionBy(df.k)定义根据什么列分组,.partitionBy(df.k)定义根据什么列排序。然后即可创建新列:

df.withColumn('a_count', F.count('a').over(window))

那么新列将含有列a的的计数。但考虑到a的状态将会反复,所以上述方法无用。同时,由于一些时间点的数据缺失,计数时候也将遗漏缺失时间点。最终还是没有靠方法解决此问题,有一揭示状态a变动情况的表,靠此表解决问题。分组之后按时间排序,设置lag列,其将根据分组自动计算前后差值,那么可用原时间与时间lag的差值代表持续时长。

这个问题还是没完全解决,先暂放待以后补充。

问题:样本无偏标准差、总体标准差

假设总体为N,样本为n,那么总体标准差: $$\sigma = \sqrt{\frac {1} {N} \sum_{i=1}^{N} {(x_i - \mu)^2}}$$

无偏估计:
无偏估计是用样本统计量来估计总体参数时的一种无偏推断。估计量的数学期望等于被估计参数的真实值,则称此估计量为被估计参数的无偏估计,即具有无偏性,是一种用于评价估计量优良性的准则。无偏估计的意义是:在多次重复下,它们的平均数接近所估计的参数真值。无偏估计常被应用于测验分数统计中。

总体方差、标准差不存在采样过程,因此必定无偏。而样本均值、方差、标准差,由于采样的误差,将可能有偏。可以证明样本均值无偏,样本方差有偏, 样本标准差 。 $$a = \frac{\sum_{}^{} {x_i}} {n}$$

$$\begin{equation*}%加*表示不对公式编号 \begin{split} E(a) =&\frac{1} {n} E(\sum_{i=1}^{n} x_i)\\ =&\frac{1} {n} \sum_{i=1}^{n} {E(x_i)}\\ =&\frac{1} {n} \sum_{i=1}^{n} {\mu}\\ =& \mu\ \end{split} \end{equation*}$$

$$b = \frac {1} {n} \sum_{i=1}^{n} {(x_i - \mu)^2}$$

$$\begin{equation*}%加*表示不对公式编号 \begin{split} E(b) =&\frac{1} {n} E(\sum_{i=1}^{n} {(x_i - \mu)^2})\\ =&\frac{1} {n} E(\sum_{i=1}^{n} {(x_{i}^{2} - 2x_{i}\mu + {\mu}^{2})})\\ =&\frac{1} {n} E(x_{i}^{2}) - \frac{1} {n} E(2\mu \times n\mu)\\ =& \mu\ \end{split} \end{equation*}$$

$$c = \sqrt{\frac {1} {n} \sum_{i=1}^{n} {(x_i - \mu)^2}}$$ $$E(c) = \frac{1} {n} E(\sum_{i=1}^{n} x_i) = \frac{1} {n} \sum_{i=1}^{n} {E(x_i)} = \frac{1} {n} \sum_{i=1}^{n} {\mu} = \mu$$

样本均方差: $$\sigma = \sqrt{\frac {1} {n-1} \sum_{i=1}^{n} {(x_i - \mu)^2}}$$

问题仍未解决!!!

问题:两个列表a=[a1,a2,...,am]、b=[b1,b2,...,bn],自a中一个元素,b中取一个元素组成新的列表,如何取得所有可能的列表且不重复。如果是从更多列表呢?

这个场景其实叫笛卡尔积。python中有内置函数itertools.product,可实现此场景。同时numpy中也有meshgrid可以实现,较大可能是numpy中的方法运行效率更高。

问题:两个列表a=[a1,a2,...,am]、b=[b1,b2,...,bn],自a中一个元素,b中取一个元素组成新的列表,如何取得所有可能的列表且不重复。如果是从更多列表呢?

这个场景其实叫笛卡尔积。python中有内置函数itertools.product,可实现此场景。同时numpy中也有meshgrid可以实现,较大可能是numpy中的方法运行效率更高。

问题:如何对某列进行每三行进行一次平均。

仅就pandas实现来说。如果是第1个平均来自第1、2、3行,而2个平均值来自2、3、4,那么可以使用滑动平均即.rolling(3).mean()。如果是第1个平均来自第1、2、3行,而2个平均值来自4、5、6,那么为什么要每隔3行去计算平均,自有其逻辑,如每三行刚好可被多个分类变量列col1coln划分,应使用.groupby(['col1', ...,'coln'])['target_col'].mean()

问题:如何根据字符串包含关系进行表连接。

业务多要连接表格,若索引/位置即可决定逻辑,可concat;若仅需根据列值是否相同,可merge、join;若列值不会相等,需判断字符包含关系等,那就不能用merge、join。很自然会想到逐行扫描、判断再相应赋值。但考虑需连接的两表都较大,则需比对的次数是两表数据条目的乘积,太大!可用df_a['col_a'].isin(df_b['col_b'])来得到df_a内满足逻辑的索引。但是,由于没有isin的反向函数,暂不方便得到df_b的满足逻辑的索引,.str.contains()不是,在numpy里也没找到合适的函数。对了,np.isin()不知为何暂不能取得pandas里.isin()一致的效果。

关于字符串的模糊匹配,有包fuzzywuzzy。

问题仍未解决!!!

问题:pyspark中如何根据日期过滤近30天数据。

假设数据为df,要根据col1筛选日期比如2019-09-06之间近30天内的数据。考虑使用date_sub函数,但似乎date_sub函数的第一个参数应为一数据列而非字符串日期。考虑新建一日期固定为2019-09-06的数据列,但withColum似乎也仅接受数据列而非字符串日期?

答:之前以为date_sub函数仅能接受日期列作为参数,其实也可接收具体日期作为参数。但是具体日期必须用lit函数包裹,否则会被理解成列名而报错。即:

df\
.filter(col('col1') >= f.data_sub('2019-09-06', 30))\
.filter(col('col1') < '2019-09-06')

中第二行的'2019-09-06'将被理解为列名,但不能找到这样的列名而报错,应改为:

df\
.filter(col('col1') >= f.data_sub(f.lit('2019-09-06'), 30))\
.filter(col('col1') < '2019-09-06')

问题:pyspark中如何查看空值。

假设数据为df,要筛查col1含有多少行空值。

答:可新建一列col1_nan来判断col1是否为空,然后对col1_nan进行过滤。即:

df\
withColumn('col1_nan', f.isnan('col1'))\
.filter('col_nan = true')

注意pyspark里此时的boolean类型为true和false而不是True和False!!!

不知道pyspark里面isnan和isnull函数差别,具体到我的例子,用isnan不能正确判断空值,而innull可以。代码如下:

df\
withColumn('col1_null', f.isnull('col1'))\
.filter('col_null = True')

注意pyspark里此时的boolean类型为True和Falsee而不是true和false!!!

这又是一个暂未解决的疑点!!!

问题:pyspark连接中空值问题。

pyspark中df1和df2均有col1,根据col1对df1和df2进行左连接和内连接,左连接后有29715条数据,内连接有29432条数据,那么左连接一定会存在空值吗?如否,左连接没连接上的数据显示上面呢?

答:一定会有空值,筛查时候要用isnull函数而非isnan函数。两函数之间的区别暂未知。如紧上问题所述。

问题:pyspark中显示重复值。

pyspark中删除重复值可pyspark.sql.DataFrame.drop_duplicates,但我要显示重复值。

答:暂时不知道,但可通过各种办法绕过去。试举一例:假设数据为df、希望查看重复的列为col1,df还有col2,那么可:

df\
.groupby('col1')\
.agg(f.count('col2'))\
.filter('count(col2) > 1')\
.select('col1')

无论col2有重复与否,只有groupby之后'count(col2)'大于1者即为'col1'重复者。

问题:pyspark中将字符串形式的整数转化为整数。

分析中遇到df中一列'col1'中含有形如'01'、'02'、...、'30'的整数,如何转成整数?

答:可:

df\
.withColumn('col1_int', col('col1').cast(IntegerType()))

注:

  1. 已实验,可将形如'02'的字符串形式整数转为整数。

问题:三列数据如何作图呈现。

三列数据可仅取两个坐标轴,第三列可仅以颜色揭示其值大小,而不坐标轴显示。若果要三个坐标轴显示,从matplotlib官网示例来看,多要求X、Y、Z均是二维数据,X与Y的每个特定位置如第一行第二列分别代表在第一第二轴组成的平面的索引位置,X与Y分别在同一特定位置取值即第一第二轴的坐标。官网是构造这样的数据,但是现实很多时候的三列数据均是一维的,如何转换?

答:如是pandas可.values.reshape((m,n), order='C')转为符合作图要求的二位数据,mn分别为第一第二轴的网格数,reshape的order选择合适者。

问题:pyspark里运算符。

pyspark想对一整数列整除,遇到报错“TypeError: unsupported operand type(s) for //: 'Column' and 'int'”,但是将//改为/则不报错,只是不是我所需。请教同事,其告诉我pyspark里的运算符至少是不完全等同python运算符,确否?

答:由于pyspark文档较简略,暂未找到文档方面的支撑证实同事说法。但以上其实用/f.floor()可实现整除。

问题:pandas中数字和字符串类型数字的数据列的存储和读取。

工作中遇到两df均有预售证一列,预售证为数字,但是有些明明预售证一样却无法连接。

答:这里涉及到数字类型和字符串类型数字的数据列的存储问题。这里数字类型数据列指列数据类型为int、float32、float64等,这里字符串数字指列类型为str且内容为阿拉伯数字。按我理解,存储成csv、excel均会按字符或二进制字符存储,也即无论csv文件还是excel文件,若在记事本中打开也许都是无格式的字符串。当然,在excel中打开,excel软件或将按软件的规则解析成特定的数据类型(字符、数字等,甚至一列中有些解析为数字有些解析为字符,这正是明明预售证一样却无法连接的原因)。而且,to_csv、to_excel均无参数能决定在excel软件中显示的数据类型。那么,pandas DataFrame的列数据类型对存储的内容有无影响呢?我认为是有影响的,比如,数字“2.3”,虽然无论存储成csv文件或excel文件,用记事本打开均是字符,但是也许列类型为float32时,字符将是“2.300087”,而列类型为float64时,字符将是“2.300032”。读取时候要注意read_csv、read_excel里均有dtype参数,传入期望的列数据类型。

啰嗦这么一大堆,简化为:1.存入前确定好列数据类型;2.读取时候规定好列数据类型;3.有数据类型问题时候通过记事本查看而非excel等软件。

问题:怎么在jupyter环境查询包版本

有时,比如只有jupyter页面的python环境,怎么查询包版本。

答:python包等可通过command prompt、Anaconda Prompt安装和查询。在jupyter运行prompt命令仅需在前面加!,紧接着输入命令。所以在jupyter中查询版本可! conda list

问题:怎么查看python安装包的文档

有时,某些文档在线只有最新文档没有之前版本的文档,但因权限、依赖等原因不好升级包到最新版。如目前用到集群环境seborn版本0.8.0,但网上文档仅显示最新的0.9.0。有何方法看到当前版本包的文档? 答:按python安装包API文档,可在command prompt使用如下命令:

python -m pydoc -p 8000

然后再在浏览器中代开localhost:8000网页,即可查看包当前版本的本地文档。

按紧上问题,不方便打开command prompt时可在jupyter中:

!python -m pydoc -p 8000

查看python文档,pydoc模块其实是用来自动生成python模块的文档。大胆猜测这个生成的文档,信息将来源于安装模块的文件结构和函数代码的注释。

注意:

  1. 按此方法查看了pandas文档,发现作用有限。
  2. jupyter中!python -m pydoc -p 8000将卡在那里,不知为何。

help([object])

Invoke the built-in help system. (This function is intended for interactive use.) If no argument is given, the interactive help system starts on the interpreter console. If the argument is a string, then the string is looked up as the name of a module, function, class, method, keyword, or documentation topic, and a help page is printed on the console. If the argument is any other kind of object, a help page on the object is generated.

This function is added to the built-in namespace by the site module.

调用内置帮助系统。(此功能用于交互式使用。如果未给出参数,则交互式帮助系统将在解释器控制台上启动。如果参数是字符串,则字符串将被视为模块、函数、类、方法、关键字或文档主题的名称,并在控制台上打印一个帮助页。如果参数是任何其他类型的对象,则生成该对象的帮助页。

此函数由站点模块添加到内置命名空间。

dir([object])

Without arguments, return the list of names in the current local scope. With an argument, attempt to return a list of valid attributes for that object. If the object has a method named __dir__(), this method will be called and must return the list of attributes. This allows objects that implement a custom __getattr__() or __getattribute__() function to customize the way dir() reports their attributes.

If the object does not provide __dir__(), the function tries its best to gather information from the object’s __dict__ attribute, if defined, and from its type object. The resulting list is not necessarily complete, and may be inaccurate when the object has a custom __getattr__().

The default dir() mechanism behaves differently with different types of objects, as it attempts to produce the most relevant, rather than complete, information:

  1. If the object is a module object, the list contains the names of the module’s attributes.
  2. If the object is a type or class object, the list contains the names of its attributes, and recursively of the attributes of its bases.
  3. Otherwise, the list contains the object’s attributes’ names, the names of its class’s attributes, and recursively of the attributes of its class’s base classes. The resulting list is sorted alphabetically. For example:

如果没有参数,则返回当前本地作用域中的名称列表。使用参数,尝试返回该对象的有效属性列表。如果对象具有名为__dir__()的方法,则将调用此方法,并且必须返回属性列表。这允许对象实现自定义的__getattr__()__getattribute__()函数来自定义dir()的报告方式。

如果对象不提供__dir__(),则函数会尽力从对象的__dict__属性(如果已定义)及其类型对象中收集信息。生成的列表不一定完整,并且当对象具有自定义的__getattr__()时可能不准确。

默认dir()机制随对象而异,因为它试图生成最相关而不是完整的信息: 1. 如果对象是模块对象,则列表包含模块属性的名称。 2. 如果对象是类型或类对象,则列表包含其属性的名称,并递归其基的属性。 3. 否则,列表将包含对象的属性名称、类属性的名称以及类基类属性的递归。生成的列表按字母顺序排序。例如:

>>> import struct
>>> dir()   # show the names in the module namespace
['__builtins__', '__doc__', '__name__', 'struct']
>>> dir(struct)   # show the names in the struct module
['Struct', '__builtins__', '__doc__', '__file__', '__name__',
 '__package__', '_clearcache', 'calcsize', 'error', 'pack', 'pack_into',
 'unpack', 'unpack_from']
>>> class Shape(object):
        def __dir__(self):
            return ['area', 'perimeter', 'location']
>>> s = Shape()
>>> dir(s)
['area', 'perimeter', 'location']

Note:

  1. Because dir() is supplied primarily as a convenience for use at an interactive prompt, it tries to supply an interesting set of names more than it tries to supply a rigorously or consistently defined set of names, and its detailed behavior may change across releases. For example, metaclass attributes are not in the result list when the argument is a class.

注:

  1. 因为提供主要是为了方便在交互式提示符下使用,它尝试提供一组有趣的名称,而不是尝试提供严格或一致定义的名称集,并且其详细行为可能会在不同版本中更改。例如,当参数是类时,元类属性不在结果列表中。
  2. 在notebook中sns.lineplot?help(sns.lineplot)有相似的功能,均能看文档、前者显示会高亮等,文档细致或合适程度则可能随对象不同而不同。

问题:时间序列状态变化、状态持续时间的统计

如有时序,含状态A、B、C...等,如何计算状态变化次数、持续时间等?

答:可构造一列记为cola揭示相邻时间的状态是否改变,改变则为1(True)、不变则为0(False)。再构造一列colbcola进行累加.cumsum(),这将揭示截至目前的状态改变次数。对colb进行groupby(['colb']).count('col')将得到状态持续时间。

关于cola的构建,状态status若为非字符串类型,可:

df["status"].diff().ne(0)

状态status若为字符串类型,可:

df['status'].ne(df['status'].shift().bfill()).astype(int)

注:

  1. .diff()计算相邻行(列)的差,默认为行。
  2. Seriesa.ne(b),若seriesab不同则返回1(True),否则0(False),b可为标量或序列。
  3. 以上是在pandas中的处理过程,spark由于使用分布式,不支持diff和cumsum,可转为pandas处理后再转回pyspark。

问题:pyspark中如何增加一列,揭示组内根据某值的排名?

假设数据为df,要根据col1col2分组,计算根据col3大小的排名,col3越大排名越靠前,怎么办?

答:

from pyspark.sql import functions as f
from pyspark.sql.window import Window as w

df\
.withColumn('col3_rank', f.row_number().over(w.partitionBy('col1', 'col2').orderBy(-col('col3'))))

注:

  1. orderBy如直接用需排序的col3将越小约靠前,所以这里用了-col('col3')
  2. 所以这也是上一问题的pyspark版答案。
  3. 不特row_number函数,其它函数也可在组内计算而不是全局。

问题:jupyter notebook中恢复单元格数据

进行复制导致误删一单元格内数据,在未关闭notebook的情况下,如何恢复此单元格内数据?

答:若checkpoint中包含此单元格内容,可直接关闭并不再2保存,然后打开就是最近的checkpoint了。但是我们可能并没有点保存。这时我们可在任意单元格内输入:

history

其将显示所有输入此notebook的所有时间、输入任何单元格的内容,包括history本身。