他山石

[转]python Pandas 常用方法备忘

关键缩写和包导入
缩写:

df:任意的Pandas DataFrame对象
s:任意的Pandas Series对象
导入包:

import pandas as pd
import numpy as np

导入数据
pd.read_csv(filename):从CSV文件导入数据
pd.read_table(filename):从限定分隔符的文本文件导入数据
pd.read_excel(filename):从Excel文件导入数据
pd.read_sql(query, connection_object):从SQL表/库导入数据
pd.read_json(json_string):从JSON格式的字符串导入数据
pd.read_html(url):解析URL、字符串或者HTML文件,抽取其中的tables表格
pd.read_clipboard():从你的粘贴板获取内容,并传给read_table()
pd.DataFrame(dict):从字典对象导入数据,Key是列名,Value是数据

导出数据
df.to_csv(filename):导出数据到CSV文件
df.to_excel(filename):导出数据到Excel文件
df.to_sql(table_name, connection_object):导出数据到SQL表
df.to_json(filename):以Json格式导出数据到文本文件

创建测试对象
pd.DataFrame(np.random.rand(20,5)):创建20行5列的随机数组成的DataFrame对象
pd.Series(my_list):从可迭代对象my_list创建一个Series对象
df.index = pd.date_range(‘1900/1/30’, periods=df.shape[0]):增加一个日期索引

查看、检查数据
df.head(n):查看DataFrame对象的前n行
df.tail(n):查看DataFrame对象的最后n行
df.shape():查看行数和列数
df.info():查看索引、数据类型和内存信息
df.describe():查看数值型列的汇总统计
s.value_counts(dropna=False):查看Series对象的唯一值和计数
df.apply(pd.Series.value_counts):查看DataFrame对象中每一列的唯一值和计数

数据选取
df[col]:根据列名,并以Series的形式返回列
df[[col1, col2]]:以DataFrame形式返回多列
s.iloc[0]:按位置选取数据
s.loc[‘index_one’]:按索引选取数据
df.iloc[0,:]:返回第一行
df.iloc[0,0]:返回第一列的第一个元素

数据清理
df.columns = [‘a’,’b’,’c’]:重命名列名
pd.isnull():检查DataFrame对象中的空值,并返回一个Boolean数组
pd.notnull():检查DataFrame对象中的非空值,并返回一个Boolean数组
df.dropna():删除所有包含空值的行
df.dropna(axis=1):删除所有包含空值的列
df.dropna(axis=1,thresh=n):删除所有小于n个非空值的行
df.duplicated():判断重复数据记录
df.drop_duplicates():删除数据记录,可指定特定列或全部
df.fillna(x):用x替换DataFrame对象中所有的空值
s.astype(float):将Series中的数据类型更改为float类型
s.replace(1,’one’):用‘one’代替所有等于1的值
s.replace([1,3],[‘one’,’three’]):用’one’代替1,用’three’代替3
df.rename(columns=lambda x: x + 1):批量更改列名
df.rename(columns={‘old_name’: ‘new_ name’}):选择性更改列名
df.set_index(‘column_one’):更改索引列
df.rename(index=lambda x: x + 1):批量重命名索引

数据处理:Filter、Sort和GroupBy
df[df[col] > 0.5]:选择col列的值大于0.5的行
df.sort_values(col1):按照列col1排序数据,默认升序排列
df.sort_values(col2, ascending=False):按照列col1降序排列数据
df.sort_values([col1,col2], ascending=[True,False]):先按列col1升序排列,后按col2降序排列数据
df.groupby(col):返回一个按列col进行分组的Groupby对象
df.groupby([col1,col2]):返回一个按多列进行分组的Groupby对象
df.groupby(col1)[col2]:返回按列col1进行分组后,列col2的均值
df.pivot_table(index=col1, values=[col2,col3], aggfunc=max):创建一个按列col1进行分组,并计算col2和col3的最大值的数据透视表
df.groupby(col1).agg(np.mean):返回按列col1分组的所有列的均值
data.apply(np.mean):对DataFrame中的每一列应用函数np.mean
data.apply(np.max,axis=1):对DataFrame中的每一行应用函数np.max

数据合并
df1.append(df2):将df2中的行添加到df1的尾部
df.concat([df1, df2],axis=1):将df2中的列添加到df1的尾部
df1.join(df2,on=col1,how=’inner’):对df1的列和df2的列执行SQL形式的join

数据统计
df.describe():查看数据值列的汇总统计
df.mean():返回所有列的均值
df.corr():返回列与列之间的相关系数
df.count():返回每一列中的非空值的个数
df.max():返回每一列的最大值
df.min():返回每一列的最小值
df.median():返回每一列的中位数
df.std():返回每一列的标准差

转自:https://www.cnblogs.com/feiqixia/p/11241925.html

Hello World

Untiy笔记–鼠标跟随移动

这里的使用场景是飞机的移动,飞机跟随鼠标移动,但飞机会有移动速度上限.
实际使用时,最大速度bigSpeed的数值可以通过unity开发工具设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    public float bigSpeed; //每毫秒最大的移动距离
    private Transform fighterTransform; //游戏对象
    private long lastUpdate; //记录最近一次update的时间
 
    private void Update(){
        //因为仅需要每次移动时刷新位置,所以不需要放在FixedUpdate里
        FollowMouseMove();
    }
 
    private void FollowMouseMove(){
        long now = (System.DateTime.Now.Ticks - 621355968000000000)/10000;
        //首先获取飞机当前位置
        Vector3 fightPos = fighterTransform.position;
        //鼠标当前位置,ScreenToWorldPoint用于转化为游戏内坐标体系
        Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        //2D游戏,抛去z轴信息
        mousePos = new Vector3(mousePos.x, mousePos.y, 0f);
        //飞机鼠标位置的距离
        float distance = Vector3.Distance(fightPos-fix, mousePos);
        //两帧之间最大移动距离,bigSpeed是每毫秒的最大移动距离 Update的调用时间并不准确,为了速度均衡,这里根据时间差值来计算
        float maxLen = ((float)(now - lastUpdate))*bigSpeed;
        Vector3 targetPos; //飞机的目标位置
        //飞机向鼠标位置移动  未超过最大距离
        if(distance <= maxLen){
            targetPos = mousePos;
        }else{
            //三角计算
            float dx = (maxLen*(mousePos.x-fightPos.x))/distance;
            float dy = (maxLen*(mousePos.y-fightPos.y))/distance;
            Vector3 dpos = new Vector3(dx, dy, 0f);
            targetPos = fighterTransform.position + dpos;
        }
        //TODO:targetPos是否超出屏幕范围的判断
        fighterTransform.position = targetPos; //将目标位置复制的游戏对象
        lastUpdate = now;
    }

充分使用Vector3自带运算,对计算过程做精简

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    private void FollowMouseMove(){
        long now = (System.DateTime.Now.Ticks - 621355968000000000)/10000;
        Vector3 fightPos = fighterTransform.position;
        Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);  //WorldToScreenPoint
        mousePos = new Vector3(mousePos.x, mousePos.y, 0f);
        float distance = Vector3.Distance(fightPos, mousePos); //当前距离
        float rank;
        float maxLen = ((float)(now - lastUpdate))*bigSpeed; //实际可以移动的最大距离
        if(distance < maxLen){
            rank = 1;
        }else{
            rank = maxLen/distance;
        }
        Vector3 dpos = (mousePos - fightPos)*rank;
        Vector3 targetPos = fighterTransform.position + dpos;
        //CanNotOUtCamera 出界判断模块
        targetPos = CanNotOUtCamera(targetPos, fighterTransform.localScale);
        fighterTransform.position = targetPos;
        lastUpdate = now;
    }
Hello World

Unity笔记–利用预制体动态创建对象

使用Unity制作射击游戏,屏幕内的每一个子弹都需要一个游戏对象,如果是单发武器还好,项目里复制几个对象,然后下面的代码就能不断循环使用。

1
2
    transform.SetAsLastSibling();
    bulletsTransform = transform.GetChild(0);

但如果需要使用连发武器,比如加特林之类的,同一时间屏幕上可能会出现许多的子弹。如果还是事先复制一堆子弹对象,就显得特别low,这里就需要动态创建子弹对象了。
首先,新建预制体子弹对象“Bullet1”,然后将其拖入Assets/Resources目录内(只有名为“Resources”目录内的资源才能动态加载)。
然后就可以在代码内创建、使用预制体对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
    //代码片段1,加载预制体, 创建对象
    GameObject bullet = Resources.Load("Bullet1") as GameObject; //加载预制体
    bullet = Instantiate(bullet); //使用这种方式加载预制体,必须序列化后才能使用
    bullet.transform.parent = cannonsTransform; //设置父级对象
    bullet.transform.localScale = bulltScale; //设置大小。。。预制体似乎为包含拖到修改大小的信息,这里使用中一个Vector3对象重新设置其大小
    bullet.transform.position = beginPos; //使用一个Vector3对象,设置初始位置
    runingBullets.Add(bullet.transform); //加入到队列
 
    //代码片段2,销毁预制体
    if(...){
        Destroy(runingBullets[i].gameObject); //销毁对象
        runingBullets.RemoveAt(i); //移出队列
    }

再unity中,创建对象是很耗资源的操作,正式项目建议创建后不要轻易销毁,而是通过SetActive(false/true)循环使用。
——-
原创内容,转载请注明出处:http://www.jiangkl.com/2021/04/unity_new_prefabs

Hello World

adb指令备忘

adb devices #查看连接设备
adb -s cf27456f shell # 指定连接设备使用命令
adb install test.apk # 安装应用
adb install -r demo.apk #安装apk 到sd 卡:
adb uninstall cn.com.test.mobile #卸载应用,需要指定包
adb uninstall -k cn.com.test.mobile #卸载app 但保留数据和缓存文件
adb shell pm list packages #列出手机装的所有app 的包名
adb shell pm list packages -3 #列出除了系统应用的第三方应用包名
adb shell pm clear cn.com.test.mobile #清除应用数据与缓存
adb shell am start -ncn.com.test.mobile/.ui.SplashActivity #启动应用
adb shell dumpsys package #包信息Package Information
adb shell dumpsys meminfo #内存使用情况Memory Usage
adb shell am force-stop cn.com.test.mobile #强制停止应用
adb logcat #查看日志
adb logcat -c #清除log 缓存
adb reboot #重启
adb get-serialno #获取序列号
adb shell getprop ro.build.version.release #查看Android 系统版本
adb shell top -m 10 #查看占用内存前10 的app
adb push #从本地复制文件到设备
adb pull #从设备复制文件到本地
adb bugreport #查看bug 报告
adb help #查看ADB 帮助

Hello World

一个生成数独数组的暴力算法

这是一个通过随机数生成9*9矩阵,然后判断是否符合数独条件的算法,成功率大概在0.3%
这个方法比较暴力,生成随机数时没有做过多的判断,不过。。。可用,php,30秒内跑50000次毫无压力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
    //入口方法,循环调取t1
    function t0(){
    	$dr 		= [];
    	$poolCount 	= 50000;
    	for($i = 0; $i < $poolCount; $i++){
    		$dr[$i] = t1($i);
    	}
    	$succ		= 0;
        //打印成功数组
    	foreach ($dr as $j => $sar){
    		if(!$sar) continue;
    		$succ++;
    		echo $j.':<br>';
	        foreach($sar as $ar){
	        	echo implode(', ', $ar).'<br>
	';
	        }
    	}
    	echo $poolCount.'次循环,共'.$succ.'成功,成功率 '.(round(($succ*10000)/$poolCount)/100).'% :<br>';
    	exit;
    }
    //核心方法,成功生成符合条件的数独数组,返回数组
    //如不成功,返回false
    private function t1($poolNo){
        //准备记录速度数组的二位数组,初始化都是0
        $sar			= build2ArrZero(9);
        $don			= 0;//当前循环次数
        //数独数组生成思路: 按格填数,单个格填数失败,退出
        $sl 			= [1, 2, 3, 4, 5, 6, 7, 8, 9];
        $sx 			= build2ArrZero(9+1); //按行,$x, 标记每个数有没有出现过
        $sy 			= build2ArrZero(9+1); //按行,$y, 标记每个数有没有出现过
        $s33			= [];//标记小33矩阵是否出现过
        for($x = 0; $x < 9; $x++){
	        for($y = 0; $y < 9; $y++){
				$dx		= $x > 2 ? ($x > 5 ? 6 : 3) : 0;//小33矩阵范围判断
				$dy		= $y > 2 ? ($y > 5 ? 6 : 3) : 0;
				if(empty($s33[$dx.'-'.$dy])){
					$s33[$dx.'-'.$dy] = build2ArrZero(10)[0];
				}
	        	for($nsn = 0; ; $nsn++){
	        		if($don > 10000) break;//循环次数限制
	        		$don++;
	        		if($nsn > 12){
	        			echo '第'.$poolNo.'次----, ', $x, ', ', $y.',过循环出错, 循环次数:', $don, '<br>'; 
						return false;  //随机两次、累加10次,在不成功,既视为此次循环失败 退出
	        		}else if($nsn > 2){
		        		$n		= (($n+1)%9)+1;
	        		}else{
		        		$n		= (rand(1, 9999)%9)+1;
	        		}
	        		$backRea	= '';
	        		//行列检查
	        		if($sx[$x][$n] == 1){
	        		//	echo $poolNo.'--x, ', $don, ', ', $x, ', ', $y, ', ', $n.',$x跳出', '<br>'; 
	        			continue;
	        		}
	        		if($sy[$y][$n] == 1){
	        		//	echo $poolNo.'--y, ', $don, ', ', $x, ', ', $y, ', ', $n.',$y跳出', '<br>'; 
	        			continue;
	        		}
	        		//小33矩阵检查
	        		if($s33[$dx.'-'.$dy][$n] == 1){
					//	echo $poolNo, '--', $dx.'-'.$dy, ', ', $n.',小 3-3 检查跳出', '<br>';
						continue;
	        		}
		       		$sar[$x][$y] 	= $n;
		       		$sx[$x][$n] 	= 1;
		       		$sy[$y][$n] 	= 1;
					$s33[$dx.'-'.$dy][$n] = 1;
		       		break;
	        	}
	        }
        }
        echo $poolNo.'--------------------成功', ', 循环次数:', $don, '<br>';
        return $sar;
    }
    //辅助方法,生成00数组
    function build2ArrZero($llen){
        for($i = 0; $i < $llen; $i++){
            $sar[$i]	= [];
            for($j = 0; $j < $llen; $j++){
                $sar[$i][]	= 0;
            }
        }
        return $sar;
    }

转载请注明出处:http://www.jiangkl.com/2021/02/数独发生器

他山石

几个简单的推荐算法图解(转)

1. 基于内容的推荐:

上图给出了基于内容推荐的一个典型的例子,电影推荐系统,首先我们需要对电影的元数据有一个建模,这里只简单的描述了一下电影的类型;然后通过电影的元数据发现电影间的相似度,因为类型都是“爱情,浪漫”电影 A 和 C 被认为是相似的电影(当然,只根据类型是不够的,要得到更好的推荐,我们还可以考虑电影的导演,演员等等);最后实现推荐,对于用户 A,他喜欢看电影 A,那么系统就可以给他推荐类似的电影 C。

2. 基于用户的协同过滤推荐(User-based Collaborative Filtering Recommendation)

上图示意出基于用户的协同过滤推荐机制的基本原理,假设用户 A 喜欢物品 A、物品 C,用户 B 喜欢物品 B,用户 C 喜欢物品 A 、物品 C 和物品 D;从这些用户的历史喜好信息中,我们可以发现用户
A 和用户 C 的口味和偏好是比较类似的,同时用户 C 还喜欢物品 D,那么我们可以推断用户 A 可能也喜欢物品 D,因此可以将物品 D 推荐给用户 A。

3. 基于项目的协同过滤推荐(Item-based Collaborative Filtering Recommendation)

上图表明基于项目的协同过滤推荐的基本原理,用户A喜欢物品A和物品C,用户B喜欢物品A、物品B和物品C,用户C喜欢物品A,从这些用户的历史喜好中可以认为物品A与物品C比较类似,喜欢物品A的都喜欢物品C,基于这个判断用户C可能也喜欢物品C,所以推荐系统将物品C推荐给用户C。
———
转自:https://www.zhihu.com/question/19971859

Hello World

Cocos学习笔记——碰撞回调(1)

接上篇小球落地,如果想让小球落地后反弹,要怎么做哪?
cocos的物理引擎提供了碰撞回调,需要如下步骤开启:
1. 参照前一篇,配置碰撞双方的RigidBody,开启重力引擎
2. 菜单选择“项目”-“项目设置”-“分组管理”,添加分组:ground、balls(这里,物理引擎的碰撞并不需要勾选balls与ground的碰撞关系)
3. “层级管理器”里,分别选择ground、ball节点,配置ground、balls分组
4. 脚本的onLoad内开启重力引擎,小球的脚本内添加碰撞回调:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
....
  onLoad(){
    cc.director.getPhysicsManager().enabled = true;
  }
....
  //碰撞开始时的回调,self为碰撞“主动方”, other为碰撞“被动方”
  onBeginContact(contact, self, other){
    let v = self.body.linearVelocity;
    v.y = 1200;//设置一个向上的速度
    self.body.linearVelocity = v;
    //注意,下面这种写法是无效的:
    //self.body.linearVelocity.y = 1200;
  }
  //碰撞处理结束时的回调
  onEndContact(contact, self, other){
 
  }
....

注意:
a. onBeginContact、onEndContact是系统指定的碰撞引擎的回调方法,不需要绑定,也不能改名
b. 除了“物理组件”引起的碰撞,cocos还有正常运动时产生的碰撞,此时的回调方法是onCollisionEnter,详细使用方法将放到下一篇笔记里

演示:http://dev.jiangkl.com/ex/dlx2
转载请注明出处:http://www.jiangkl.com/2020/05/cocos_碰撞

Hello World 日志

Cocos学习笔记——开启重力引擎

使用cocos自带的重力引擎起作用,这里以小球下落到地面为例,需要下面几步:
1. 添加“地面”节点,并添加RigidBody组件,type选Static;为了更好地演示“地面”的桌面,还需要配置碰撞组件PhysicsBoxCollider,也可以选择、调整为其他形状
2. 添加“小球”节点,并添加RigidBody组件,type选Dynamic,配置小球所受重力加速度GraviteScale;配置碰撞组件PhysicsCircleCollider,因为是球,所以这里选的是“原型”
3. 脚本的onLoad内开启重力引擎:

1
2
3
4
5
6
....
  onLoad(){
    cc.director.getPhysicsManager().enabled = true;
    cc.director.getPhysicsManager().gravity = cc.v2(0, -320);
  }
....

上面1、2两步,都可以在CocosCreator的可视化界面内完成配置,只要第3步需要写js

演示:http://dev.jiangkl.com/ex/dlx
转载请注明出处:http://www.jiangkl.com/2020/05/cocos_gravity

Hello World 他山石

defineProperty

学习VUE“双向绑定”的实现,DOM变化时,同步给js变量,这一层比较容易理解,使用DOM的事件绑定就好了;但是当js变量发送变化时,是如何监控到、然后更新到DOM的,这点就比较有意思的。
看VUE代码,里面使用了ES5新加入的“Object.defineProperty()”,属性拦截器

看名字就比较好理解,使用defineProperty定义的属性,可以针对getter,和setter操作做监控、拦截,比如下面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let o = {};
Object.defineProperty(o, 'b', {
  configurable: true,
  enumerable: true,
  get: function(){
    console.log('get run');     //log1
  },
  set: function(v){
    console.log('set run', v);  //log2
  }
});
 
setInterval(function(){
  o.b = new Date().toLocaleString();
  console.log('o.b, ', o.b);     //log3  undefined
}, 3000);

这样,每隔3秒,log2,o.b赋值时,log2,就会被打印出来
但是,下面的反应比较奇怪,getter也被拦截了,log3位置,打印出来的是“undefined”。。。
这是因为getter里没有返回值
但是如果你胆敢在getter“return this.b”,运行时就会死循环,因为如果this.b又会去调getger
(是的,这就是js。。。增加一个看似“美丽强大”的新特性的同时,还给你附加几个坑,等你往里跳。。。。。)
那么,还能不能让人好好使用这个拦截器哪?
当然可以,这里,我们可以加一个“中间变量”过渡,setter时,给中间变量赋值;getter时,return这个中间变量,就不会死循环了

当然,还可以借助经典的“function-Class”定义,对整个过程做封装,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function O1(){
  let v1;     //中间变量
 
  Object.defineProperty(this, 'v1', {
    get: function(){
      console.log('get run', v1);
      return v1;
    },
    set: function(v){
      v1 = v;
      console.log('set run', v);
    }
  });
}
 
var o1 = new O1();
 
setInterval(function(){
  o1.v1 = new Date().toLocaleString();
  console.log('o1.v1, ', o1.v1);
}, 3000);

———
转载请注明出处: http://www.jiangkl.com/2019/06/js_defineproperty

Hello World

python读取csv/json/xml

python(3.x)读取csv:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import csv
 
filename = 'xxx.csv'
fi = [] 
ls = []
 
with open(filename, 'r', encoding='gbk') as csvfile:
    reader = csv.reader(csvfile)
    fi = next(reader)
    for lr in reader:
        ls.append(lr)
 
for lr in ls[:5]:
    print(lr)

当然,使用专业类库,会更简单:

1
2
3
4
5
6
7
import pandas as pd
 
filename = 'xxx.csv'
 
data = pd.read_csv(filename, encoding='gbk')
 
print(data.head(5))

读取json:

1
2
3
4
5
6
7
8
import json
 
filename = 'xxx.json'
 
with open(filename) as f:
    jsondata = json.load(f)
 
print(jsondata)

当然,pandas里也有更高效的读取json的read_json(),不过用它读取多维不定格式的json时,会报错“ValueError: arrays must all be same length”,这里就不再演示了

读取xml,并转变为json:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import json
import xml.etree.ElementTree as ET
import xmltodict
 
filename = 'xxx/s1.xml'
 
tree = ET.parse(filename)
xmldata = tree.getroot()
 
xmlstr = ET.tostring(xmldata, encoding='utf8', method='xml')
xmldict = xmltodict.parse(xmlstr, encoding='utf8')
 
datadict = dict(xmldict)
 
print(datadict)
 
filename2 = 'xxxx/s1.json'
with open(filename2, 'w+') as jsonfile:
    json.dump(datadict, jsonfile, indent=4, sort_keys=True)

注:
1. xmltodict可能需要安装:pip install xmltodict
2. xmltodict.parse对xml格式要求较严格,如果某节点字符串开头第一个字符是数值,createElement时可能会报错